@jsenv/https-local 1.0.5 → 1.0.8
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 +9 -17
- package/package.json +14 -15
- package/src/certificate_authority.js +15 -15
- package/src/certificate_for_localhost.js +5 -3
- package/src/hosts_file_verif.js +8 -6
- package/src/internal/authority_file_infos.js +0 -1
- package/src/internal/hosts/write_line_hosts.js +2 -2
- package/src/internal/linux/chrome_linux.js +5 -9
- package/src/internal/linux/firefox_linux.js +5 -9
- package/src/internal/linux/linux_trust_store.js +14 -18
- package/src/internal/linux/nss_linux.js +8 -11
- package/src/internal/mac/chrome_mac.js +3 -3
- package/src/internal/mac/firefox_mac.js +5 -10
- package/src/internal/mac/mac_keychain.js +11 -16
- package/src/internal/mac/nss_mac.js +8 -8
- package/src/internal/nssdb_browser.js +27 -37
- package/src/internal/unsupported_platform/unsupported_platform.js +2 -2
- package/src/internal/windows/chrome_windows.js +4 -4
- package/src/internal/windows/firefox_windows.js +6 -6
- package/src/internal/windows/windows_certutil.js +11 -16
- package/src/internal/logs.js +0 -23
package/README.md
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
# https local
|
|
1
|
+
# https local [](https://www.npmjs.com/package/@jsenv/https-local)
|
|
2
2
|
|
|
3
|
-
A programmatic way to generate locally trusted certificates
|
|
4
|
-
|
|
5
|
-
[](https://www.npmjs.com/package/@jsenv/https-local)
|
|
6
|
-
[](https://github.com/jsenv/https-local/actions?workflow=main)
|
|
7
|
-
[](https://codecov.io/gh/jsenv/https-local)
|
|
8
|
-
|
|
9
|
-
# Presentation
|
|
3
|
+
A programmatic way to generate locally trusted certificates.
|
|
10
4
|
|
|
11
5
|
Generate certificate(s) trusted by your operating system and browsers.
|
|
12
6
|
This certificate can be used to start your development server in HTTPS.
|
|
@@ -106,13 +100,14 @@ The rest of the documentation goes into details.
|
|
|
106
100
|
|
|
107
101
|
# Certificate expiration
|
|
108
102
|
|
|
109
|
-
|
|
103
|
+
| Certificate | Expires after | How to renew? |
|
|
104
|
+
| ----------- | ------------- | --------------------------------------- |
|
|
105
|
+
| server | 1 year | Re-run _requestCertificateForLocalhost_ |
|
|
106
|
+
| authority | 20 year | Re-run _installCertificateAuthority_ |
|
|
110
107
|
|
|
111
|
-
In the unlikely scenario where your local server is running for more than a year without interruption, restart it and you're good for one more year.
|
|
108
|
+
The **server** certificate expires after one year which is the maximum duration allowed by web browsers. In the unlikely scenario where your local server is running for more than a year without interruption, restart it and you're good for one more year.
|
|
112
109
|
|
|
113
|
-
The authority root certificate expires after 20 years which is close to the maximum allowed duration.
|
|
114
|
-
|
|
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.
|
|
110
|
+
The **authority** root certificate expires after 20 years which is close to the maximum allowed duration. 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.
|
|
116
111
|
|
|
117
112
|
# installCertificateAuthority
|
|
118
113
|
|
|
@@ -125,10 +120,7 @@ import { installCertificateAuthority } from "@jsenv/https-local"
|
|
|
125
120
|
await installCertificateAuthority()
|
|
126
121
|
```
|
|
127
122
|
|
|
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).
|
|
123
|
+
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).
|
|
132
124
|
|
|
133
125
|
Find below logs written in terminal when this function is executed.
|
|
134
126
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/https-local",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "A programmatic way to generate locally trusted certificates",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"/main.js"
|
|
32
32
|
],
|
|
33
33
|
"scripts": {
|
|
34
|
-
"eslint": "
|
|
34
|
+
"eslint": "npx eslint . --ext=.js,.mjs",
|
|
35
35
|
"importmap": "node ./script/importmap/importmap.mjs",
|
|
36
36
|
"performances": "node --expose-gc ./script/performance/generate_performance_report.mjs --log",
|
|
37
37
|
"test": "node ./script/test/test.mjs",
|
|
@@ -49,27 +49,26 @@
|
|
|
49
49
|
"playwright-install": "npx playwright install-deps && npx playwright install"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@jsenv/filesystem": "
|
|
52
|
+
"@jsenv/filesystem": "3.1.0",
|
|
53
|
+
"@jsenv/log": "1.5.1",
|
|
53
54
|
"@jsenv/logger": "4.0.1",
|
|
54
55
|
"command-exists": "1.2.9",
|
|
55
|
-
"
|
|
56
|
-
"node-forge": "1.2.1",
|
|
56
|
+
"node-forge": "1.3.1",
|
|
57
57
|
"sudo-prompt": "9.2.1",
|
|
58
|
-
"supports-color": "9.2.1",
|
|
59
58
|
"which": "2.0.2"
|
|
60
59
|
},
|
|
61
60
|
"devDependencies": {
|
|
62
|
-
"@jsenv/assert": "2.
|
|
63
|
-
"@jsenv/core": "
|
|
61
|
+
"@jsenv/assert": "2.5.3",
|
|
62
|
+
"@jsenv/core": "26.0.1",
|
|
64
63
|
"@jsenv/eslint-config": "16.0.9",
|
|
65
|
-
"@jsenv/github-release-package": "1.3.
|
|
64
|
+
"@jsenv/github-release-package": "1.3.5",
|
|
66
65
|
"@jsenv/importmap-eslint-resolver": "5.2.5",
|
|
67
66
|
"@jsenv/importmap-node-module": "5.1.3",
|
|
68
|
-
"@jsenv/package-publish": "1.7.
|
|
69
|
-
"@jsenv/performance-impact": "2.2.
|
|
70
|
-
"eslint": "8.
|
|
71
|
-
"eslint-plugin-import": "2.
|
|
72
|
-
"playwright": "1.
|
|
73
|
-
"prettier": "2.
|
|
67
|
+
"@jsenv/package-publish": "1.7.2",
|
|
68
|
+
"@jsenv/performance-impact": "2.2.8",
|
|
69
|
+
"eslint": "8.12.0",
|
|
70
|
+
"eslint-plugin-import": "2.26.0",
|
|
71
|
+
"playwright": "1.20.2",
|
|
72
|
+
"prettier": "2.6.2"
|
|
74
73
|
}
|
|
75
74
|
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { readFile, writeFile, removeEntry } from "@jsenv/filesystem"
|
|
3
2
|
import { createLogger, createDetailedMessage } from "@jsenv/logger"
|
|
4
|
-
import {
|
|
3
|
+
import { UNICODE } from "@jsenv/log"
|
|
5
4
|
|
|
6
|
-
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
7
|
import {
|
|
@@ -97,7 +95,7 @@ export const installCertificateAuthority = async ({
|
|
|
97
95
|
)
|
|
98
96
|
|
|
99
97
|
logger.info(
|
|
100
|
-
`${
|
|
98
|
+
`${UNICODE.OK} authority root certificate written at ${rootCertificateFileInfo.path}`,
|
|
101
99
|
)
|
|
102
100
|
return {
|
|
103
101
|
rootCertificateForgeObject,
|
|
@@ -154,7 +152,7 @@ export const installCertificateAuthority = async ({
|
|
|
154
152
|
`Authority root certificate is not on filesystem at ${rootCertificateFileInfo.path}`,
|
|
155
153
|
)
|
|
156
154
|
logger.info(
|
|
157
|
-
`${
|
|
155
|
+
`${UNICODE.INFO} authority root certificate not found in filesystem`,
|
|
158
156
|
)
|
|
159
157
|
return generate()
|
|
160
158
|
}
|
|
@@ -163,14 +161,14 @@ export const installCertificateAuthority = async ({
|
|
|
163
161
|
`Authority root certificate private key is not on filesystem at ${rootCertificatePrivateKeyFileInfo.path}`,
|
|
164
162
|
)
|
|
165
163
|
logger.info(
|
|
166
|
-
`${
|
|
164
|
+
`${UNICODE.INFO} authority root certificate not found in filesystem`,
|
|
167
165
|
)
|
|
168
166
|
return generate()
|
|
169
167
|
}
|
|
170
168
|
logger.debug(
|
|
171
169
|
`found authority root certificate files at ${rootCertificateFileInfo.path} and ${rootCertificatePrivateKeyFileInfo.path}`,
|
|
172
170
|
)
|
|
173
|
-
logger.info(`${
|
|
171
|
+
logger.info(`${UNICODE.OK} authority root certificate found in filesystem`)
|
|
174
172
|
|
|
175
173
|
const rootCertificate = await readFile(rootCertificateFileInfo.path, {
|
|
176
174
|
as: "string",
|
|
@@ -186,7 +184,7 @@ export const installCertificateAuthority = async ({
|
|
|
186
184
|
)
|
|
187
185
|
if (rootCertificateValidityRemainingMs < 0) {
|
|
188
186
|
logger.info(
|
|
189
|
-
`${
|
|
187
|
+
`${UNICODE.INFO} certificate expired ${formatTimeDelta(
|
|
190
188
|
rootCertificateValidityRemainingMs,
|
|
191
189
|
)}`,
|
|
192
190
|
)
|
|
@@ -196,14 +194,14 @@ export const installCertificateAuthority = async ({
|
|
|
196
194
|
rootCertificateValidityRemainingMs / rootCertificateValidityDurationInMs
|
|
197
195
|
if (rootCertificateValidityRemainingRatio < aboutToExpireRatio) {
|
|
198
196
|
logger.info(
|
|
199
|
-
`${
|
|
197
|
+
`${UNICODE.INFO} certificate will expire ${formatTimeDelta(
|
|
200
198
|
rootCertificateValidityRemainingMs,
|
|
201
199
|
)}`,
|
|
202
200
|
)
|
|
203
201
|
return regenerate()
|
|
204
202
|
}
|
|
205
203
|
logger.info(
|
|
206
|
-
`${
|
|
204
|
+
`${UNICODE.OK} certificate still valid for ${formatDuration(
|
|
207
205
|
rootCertificateValidityRemainingMs,
|
|
208
206
|
)}`,
|
|
209
207
|
)
|
|
@@ -219,11 +217,11 @@ export const installCertificateAuthority = async ({
|
|
|
219
217
|
if (rootCertificateDifferences.length) {
|
|
220
218
|
const paramNames = Object.keys(rootCertificateDifferences)
|
|
221
219
|
logger.info(
|
|
222
|
-
`${
|
|
220
|
+
`${UNICODE.INFO} certificate attributes are outdated: ${paramNames}`,
|
|
223
221
|
)
|
|
224
222
|
return regenerate()
|
|
225
223
|
}
|
|
226
|
-
logger.info(`${
|
|
224
|
+
logger.info(`${UNICODE.OK} certificate attributes are the same`)
|
|
227
225
|
|
|
228
226
|
const rootCertificatePrivateKey = await readFile(
|
|
229
227
|
rootCertificatePrivateKeyFileInfo.path,
|
|
@@ -348,10 +346,12 @@ export const uninstallCertificateAuthority = async ({
|
|
|
348
346
|
logger.info(`Removing certificate authority files...`)
|
|
349
347
|
await Promise.all(
|
|
350
348
|
filesToRemove.map(async (file) => {
|
|
351
|
-
await
|
|
349
|
+
await removeEntry(file)
|
|
352
350
|
}),
|
|
353
351
|
)
|
|
354
|
-
logger.info(
|
|
352
|
+
logger.info(
|
|
353
|
+
`${UNICODE.OK} certificate authority files removed from filesystem`,
|
|
354
|
+
)
|
|
355
355
|
}
|
|
356
356
|
}
|
|
357
357
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { readFile, writeFile } from "@jsenv/filesystem"
|
|
2
2
|
import { createLogger, createDetailedMessage } from "@jsenv/logger"
|
|
3
|
+
import { UNICODE } from "@jsenv/log"
|
|
3
4
|
|
|
4
5
|
import {
|
|
5
6
|
createValidityDurationOfXDays,
|
|
6
7
|
verifyServerCertificateValidityDuration,
|
|
7
8
|
} from "./validity_duration.js"
|
|
8
|
-
import { okSign } from "./internal/logs.js"
|
|
9
9
|
import { getAuthorityFileInfos } from "./internal/authority_file_infos.js"
|
|
10
10
|
import { importNodeForge } from "./internal/forge.js"
|
|
11
11
|
import { requestCertificateFromAuthority } from "./internal/certificate_generator.js"
|
|
@@ -76,7 +76,7 @@ export const requestCertificateForLocalhost = async ({
|
|
|
76
76
|
const rootCertificatePrivateKeyForgeObject = pki.privateKeyFromPem(
|
|
77
77
|
rootCertificatePrivateKey,
|
|
78
78
|
)
|
|
79
|
-
logger.debug(`${
|
|
79
|
+
logger.debug(`${UNICODE.OK} certificate authority restored from filesystem`)
|
|
80
80
|
|
|
81
81
|
const serverCertificateSerialNumber =
|
|
82
82
|
certificateAuthorityData.serialNumber + 1
|
|
@@ -106,7 +106,9 @@ export const requestCertificateForLocalhost = async ({
|
|
|
106
106
|
certificatePrivateKeyForgeObject,
|
|
107
107
|
)
|
|
108
108
|
logger.debug(
|
|
109
|
-
`${
|
|
109
|
+
`${
|
|
110
|
+
UNICODE.OK
|
|
111
|
+
} server certificate generated, it will be valid for ${formatDuration(
|
|
110
112
|
serverCertificateValidityDurationInMs,
|
|
111
113
|
)}`,
|
|
112
114
|
)
|
package/src/hosts_file_verif.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createDetailedMessage, createLogger } from "@jsenv/logger"
|
|
2
|
+
import { UNICODE } from "@jsenv/log"
|
|
2
3
|
|
|
3
|
-
import { okSign, infoSign, warningSign, commandSign } from "./internal/logs.js"
|
|
4
4
|
import {
|
|
5
5
|
HOSTS_FILE_PATH,
|
|
6
6
|
readHostsFile,
|
|
@@ -38,7 +38,7 @@ export const verifyHostsFile = async ({
|
|
|
38
38
|
})
|
|
39
39
|
const missingMappingCount = missingMappings.length
|
|
40
40
|
if (missingMappingCount === 0) {
|
|
41
|
-
logger.info(`${
|
|
41
|
+
logger.info(`${UNICODE.OK} all ip mappings found in hosts file`)
|
|
42
42
|
return
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -50,7 +50,9 @@ export const verifyHostsFile = async ({
|
|
|
50
50
|
.join(EOL)
|
|
51
51
|
logger.warn(
|
|
52
52
|
createDetailedMessage(
|
|
53
|
-
`${
|
|
53
|
+
`${UNICODE.WARNING} ${formatXMappingMissingMessage(
|
|
54
|
+
missingMappingCount,
|
|
55
|
+
)}`,
|
|
54
56
|
{
|
|
55
57
|
"hosts file path": hostsFilePath,
|
|
56
58
|
"line(s) to add": linesToAdd,
|
|
@@ -61,7 +63,7 @@ export const verifyHostsFile = async ({
|
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
logger.info(
|
|
64
|
-
`${
|
|
66
|
+
`${UNICODE.INFO} ${formatXMappingMissingMessage(missingMappingCount)}`,
|
|
65
67
|
)
|
|
66
68
|
await missingMappings.reduce(async (previous, { ip, missingHostnames }) => {
|
|
67
69
|
await previous
|
|
@@ -71,10 +73,10 @@ export const verifyHostsFile = async ({
|
|
|
71
73
|
await writeLineInHostsFile(mapping, {
|
|
72
74
|
hostsFilePath,
|
|
73
75
|
onBeforeExecCommand: (command) => {
|
|
74
|
-
logger.info(`${
|
|
76
|
+
logger.info(`${UNICODE.COMMAND} ${command}`)
|
|
75
77
|
},
|
|
76
78
|
})
|
|
77
|
-
logger.info(`${
|
|
79
|
+
logger.info(`${UNICODE.OK} mapping added`)
|
|
78
80
|
}, Promise.resolve())
|
|
79
81
|
}
|
|
80
82
|
|
|
@@ -29,7 +29,7 @@ const appendToHostsFileOnWindows = async ({
|
|
|
29
29
|
hostsFilePath,
|
|
30
30
|
onBeforeExecCommand,
|
|
31
31
|
}) => {
|
|
32
|
-
const hostsFileContent = await readFile(hostsFilePath)
|
|
32
|
+
const hostsFileContent = await readFile(hostsFilePath, { as: "string" })
|
|
33
33
|
const echoCommand =
|
|
34
34
|
hostsFileContent.length > 0 && !hostsFileContent.endsWith("\r\n")
|
|
35
35
|
? `(echo.& echo ${lineToAppend})`
|
|
@@ -68,7 +68,7 @@ const appendToHostsFileOnLinuxOrMac = async ({
|
|
|
68
68
|
hostsFilePath,
|
|
69
69
|
onBeforeExecCommand,
|
|
70
70
|
}) => {
|
|
71
|
-
const hostsFileContent = await readFile(hostsFilePath)
|
|
71
|
+
const hostsFileContent = await readFile(hostsFilePath, { as: "string" })
|
|
72
72
|
const echoCommand =
|
|
73
73
|
hostsFileContent.length > 0 && !hostsFileContent.endsWith("\n")
|
|
74
74
|
? `echo "\n${lineToAppend}"`
|
|
@@ -2,11 +2,7 @@ import { existsSync } from "node:fs"
|
|
|
2
2
|
import { execSync } from "node:child_process"
|
|
3
3
|
import { resolveUrl, assertAndNormalizeDirectoryUrl } from "@jsenv/filesystem"
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
okSign,
|
|
7
|
-
infoSign,
|
|
8
|
-
warningSign,
|
|
9
|
-
} from "@jsenv/https-local/src/internal/logs.js"
|
|
5
|
+
import { UNICODE } from "@jsenv/log"
|
|
10
6
|
import {
|
|
11
7
|
nssCommandName,
|
|
12
8
|
detectIfNSSIsInstalled,
|
|
@@ -45,11 +41,11 @@ export const executeTrustQueryOnChrome = ({
|
|
|
45
41
|
const chromeBinFileExists = existsSync("/usr/bin/google-chrome")
|
|
46
42
|
|
|
47
43
|
if (chromeBinFileExists) {
|
|
48
|
-
logger.debug(`${
|
|
44
|
+
logger.debug(`${UNICODE.OK} Chrome detected`)
|
|
49
45
|
return true
|
|
50
46
|
}
|
|
51
47
|
|
|
52
|
-
logger.debug(`${
|
|
48
|
+
logger.debug(`${UNICODE.INFO} Chrome not detected`)
|
|
53
49
|
return false
|
|
54
50
|
},
|
|
55
51
|
browserNSSDBDirectoryUrl: resolveUrl(
|
|
@@ -62,14 +58,14 @@ export const executeTrustQueryOnChrome = ({
|
|
|
62
58
|
}
|
|
63
59
|
|
|
64
60
|
logger.warn(
|
|
65
|
-
`${
|
|
61
|
+
`${UNICODE.WARNING} waiting for you to close Chrome before resuming...`,
|
|
66
62
|
)
|
|
67
63
|
const next = async () => {
|
|
68
64
|
await new Promise((resolve) => setTimeout(resolve, 50))
|
|
69
65
|
if (isChromeOpen()) {
|
|
70
66
|
await next()
|
|
71
67
|
} else {
|
|
72
|
-
logger.info(`${
|
|
68
|
+
logger.info(`${UNICODE.OK} Chrome closed, resuming`)
|
|
73
69
|
// wait 50ms more to ensure chrome has time to cleanup
|
|
74
70
|
// othrwise sometimes there is an SEC_ERROR_REUSED_ISSUER_AND_SERIAL error
|
|
75
71
|
// because we updated nss database file while chrome is not fully closed
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import { existsSync } from "node:fs"
|
|
2
2
|
import { execSync } from "node:child_process"
|
|
3
3
|
import { resolveUrl, assertAndNormalizeDirectoryUrl } from "@jsenv/filesystem"
|
|
4
|
+
import { UNICODE } from "@jsenv/log"
|
|
4
5
|
|
|
5
|
-
import {
|
|
6
|
-
okSign,
|
|
7
|
-
infoSign,
|
|
8
|
-
warningSign,
|
|
9
|
-
} from "@jsenv/https-local/src/internal/logs.js"
|
|
10
6
|
import {
|
|
11
7
|
nssCommandName,
|
|
12
8
|
detectIfNSSIsInstalled,
|
|
@@ -45,11 +41,11 @@ export const executeTrustQueryOnFirefox = ({
|
|
|
45
41
|
const firefoxBinFileExists = existsSync("/usr/bin/firefox")
|
|
46
42
|
|
|
47
43
|
if (firefoxBinFileExists) {
|
|
48
|
-
logger.debug(`${
|
|
44
|
+
logger.debug(`${UNICODE.OK} Firefox detected`)
|
|
49
45
|
return true
|
|
50
46
|
}
|
|
51
47
|
|
|
52
|
-
logger.debug(`${
|
|
48
|
+
logger.debug(`${UNICODE.INFO} Firefox not detected`)
|
|
53
49
|
return false
|
|
54
50
|
},
|
|
55
51
|
browserNSSDBDirectoryUrl: resolveUrl(
|
|
@@ -62,14 +58,14 @@ export const executeTrustQueryOnFirefox = ({
|
|
|
62
58
|
}
|
|
63
59
|
|
|
64
60
|
logger.warn(
|
|
65
|
-
`${
|
|
61
|
+
`${UNICODE.WARNING} waiting for you to close Firefox before resuming...`,
|
|
66
62
|
)
|
|
67
63
|
const next = async () => {
|
|
68
64
|
await new Promise((resolve) => setTimeout(resolve, 50))
|
|
69
65
|
if (isFirefoxOpen()) {
|
|
70
66
|
await next()
|
|
71
67
|
} else {
|
|
72
|
-
logger.info(`${
|
|
68
|
+
logger.info(`${UNICODE.OK} Firefox closed, resuming`)
|
|
73
69
|
// wait 50ms more to ensure firefox has time to cleanup
|
|
74
70
|
// othrwise sometimes there is an SEC_ERROR_REUSED_ISSUER_AND_SERIAL error
|
|
75
71
|
// because we updated nss database file while firefox is not fully closed
|
|
@@ -5,13 +5,8 @@
|
|
|
5
5
|
import { existsSync } from "node:fs"
|
|
6
6
|
import { createDetailedMessage } from "@jsenv/logger"
|
|
7
7
|
import { readFile, urlToFileSystemPath } from "@jsenv/filesystem"
|
|
8
|
+
import { UNICODE } from "@jsenv/log"
|
|
8
9
|
|
|
9
|
-
import {
|
|
10
|
-
commandSign,
|
|
11
|
-
okSign,
|
|
12
|
-
infoSign,
|
|
13
|
-
failureSign,
|
|
14
|
-
} from "@jsenv/https-local/src/internal/logs.js"
|
|
15
10
|
import { exec } from "@jsenv/https-local/src/internal/exec.js"
|
|
16
11
|
import {
|
|
17
12
|
VERB_CHECK_TRUST,
|
|
@@ -44,7 +39,7 @@ export const executeTrustQueryOnLinux = async ({
|
|
|
44
39
|
verb,
|
|
45
40
|
}) => {
|
|
46
41
|
if (verb === VERB_CHECK_TRUST && certificateIsNew) {
|
|
47
|
-
logger.info(`${
|
|
42
|
+
logger.info(`${UNICODE.INFO} You should add certificate to linux`)
|
|
48
43
|
return {
|
|
49
44
|
status: "not_trusted",
|
|
50
45
|
reason: REASON_NEW_AND_TRY_TO_TRUST_DISABLED,
|
|
@@ -60,9 +55,9 @@ export const executeTrustQueryOnLinux = async ({
|
|
|
60
55
|
|
|
61
56
|
if (certificateStatus === "missing" || certificateStatus === "outdated") {
|
|
62
57
|
if (certificateStatus === "missing") {
|
|
63
|
-
logger.info(`${
|
|
58
|
+
logger.info(`${UNICODE.INFO} certificate not in linux`)
|
|
64
59
|
} else {
|
|
65
|
-
logger.info(`${
|
|
60
|
+
logger.info(`${UNICODE.INFO} certificate in linux is outdated`)
|
|
66
61
|
}
|
|
67
62
|
if (verb === VERB_CHECK_TRUST || verb === VERB_REMOVE_TRUST) {
|
|
68
63
|
return {
|
|
@@ -78,11 +73,11 @@ export const executeTrustQueryOnLinux = async ({
|
|
|
78
73
|
const updateCertificateCommand = `sudo update-ca-certificates`
|
|
79
74
|
logger.info(`Adding certificate to linux...`)
|
|
80
75
|
try {
|
|
81
|
-
logger.info(`${
|
|
76
|
+
logger.info(`${UNICODE.COMMAND} ${copyCertificateCommand}`)
|
|
82
77
|
await exec(copyCertificateCommand)
|
|
83
|
-
logger.info(`${
|
|
78
|
+
logger.info(`${UNICODE.COMMAND} ${updateCertificateCommand}`)
|
|
84
79
|
await exec(updateCertificateCommand)
|
|
85
|
-
logger.info(`${
|
|
80
|
+
logger.info(`${UNICODE.OK} certificate added to linux`)
|
|
86
81
|
return {
|
|
87
82
|
status: "trusted",
|
|
88
83
|
reason: REASON_ADD_COMMAND_COMPLETED,
|
|
@@ -91,7 +86,7 @@ export const executeTrustQueryOnLinux = async ({
|
|
|
91
86
|
console.error(e)
|
|
92
87
|
logger.error(
|
|
93
88
|
createDetailedMessage(
|
|
94
|
-
`${
|
|
89
|
+
`${UNICODE.FAILURE} failed to add certificate to linux`,
|
|
95
90
|
{
|
|
96
91
|
"certificate file": certificateFilePath,
|
|
97
92
|
},
|
|
@@ -104,7 +99,7 @@ export const executeTrustQueryOnLinux = async ({
|
|
|
104
99
|
}
|
|
105
100
|
}
|
|
106
101
|
|
|
107
|
-
logger.info(`${
|
|
102
|
+
logger.info(`${UNICODE.OK} certificate found in linux`)
|
|
108
103
|
if (verb === VERB_CHECK_TRUST || verb === VERB_ADD_TRUST) {
|
|
109
104
|
return {
|
|
110
105
|
status: "trusted",
|
|
@@ -116,11 +111,11 @@ export const executeTrustQueryOnLinux = async ({
|
|
|
116
111
|
const removeCertificateCommand = `sudo rm ${JSENV_AUTHORITY_ROOT_CERTIFICATE_PATH}`
|
|
117
112
|
const updateCertificateCommand = `sudo update-ca-certificates`
|
|
118
113
|
try {
|
|
119
|
-
logger.info(`${
|
|
114
|
+
logger.info(`${UNICODE.COMMAND} ${removeCertificateCommand}`)
|
|
120
115
|
await exec(removeCertificateCommand)
|
|
121
|
-
logger.info(`${
|
|
116
|
+
logger.info(`${UNICODE.COMMAND} ${updateCertificateCommand}`)
|
|
122
117
|
await exec(updateCertificateCommand)
|
|
123
|
-
logger.info(`${
|
|
118
|
+
logger.info(`${UNICODE.OK} certificate removed from linux`)
|
|
124
119
|
return {
|
|
125
120
|
status: "not_trusted",
|
|
126
121
|
reason: REASON_REMOVE_COMMAND_COMPLETED,
|
|
@@ -128,7 +123,7 @@ export const executeTrustQueryOnLinux = async ({
|
|
|
128
123
|
} catch (e) {
|
|
129
124
|
logger.error(
|
|
130
125
|
createDetailedMessage(
|
|
131
|
-
`${
|
|
126
|
+
`${UNICODE.FAILURE} failed to remove certificate from linux`,
|
|
132
127
|
{
|
|
133
128
|
"error stack": e.stack,
|
|
134
129
|
"certificate file": JSENV_AUTHORITY_ROOT_CERTIFICATE_PATH,
|
|
@@ -149,6 +144,7 @@ const getCertificateStatus = async ({ certificate }) => {
|
|
|
149
144
|
}
|
|
150
145
|
const certificateInLinuxStore = await readFile(
|
|
151
146
|
JSENV_AUTHORITY_ROOT_CERTIFICATE_PATH,
|
|
147
|
+
{ as: "string" },
|
|
152
148
|
)
|
|
153
149
|
if (certificateInLinuxStore !== certificate) {
|
|
154
150
|
return "outdated"
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
+
import { UNICODE } from "@jsenv/log"
|
|
2
|
+
|
|
1
3
|
import { memoize } from "@jsenv/https-local/src/internal/memoize.js"
|
|
2
|
-
import {
|
|
3
|
-
commandSign,
|
|
4
|
-
infoSign,
|
|
5
|
-
okSign,
|
|
6
|
-
} from "@jsenv/https-local/src/internal/logs.js"
|
|
7
4
|
import { exec } from "@jsenv/https-local/src/internal/exec.js"
|
|
8
5
|
|
|
9
6
|
export const nssCommandName = "libnss3-tools"
|
|
@@ -12,15 +9,15 @@ export const detectIfNSSIsInstalled = memoize(async ({ logger }) => {
|
|
|
12
9
|
logger.debug(`Detect if nss installed....`)
|
|
13
10
|
|
|
14
11
|
const aptCommand = `apt list libnss3-tools --installed`
|
|
15
|
-
logger.debug(`${
|
|
12
|
+
logger.debug(`${UNICODE.COMMAND} ${aptCommand}`)
|
|
16
13
|
const aptCommandOutput = await exec(aptCommand)
|
|
17
14
|
|
|
18
15
|
if (aptCommandOutput.includes("libnss3-tools")) {
|
|
19
|
-
logger.debug(`${
|
|
16
|
+
logger.debug(`${UNICODE.OK} libnss3-tools is installed`)
|
|
20
17
|
return true
|
|
21
18
|
}
|
|
22
19
|
|
|
23
|
-
logger.debug(`${
|
|
20
|
+
logger.debug(`${UNICODE.INFO} libnss3-tools not installed`)
|
|
24
21
|
return false
|
|
25
22
|
})
|
|
26
23
|
|
|
@@ -28,13 +25,13 @@ export const getCertutilBinPath = () => "certutil"
|
|
|
28
25
|
|
|
29
26
|
export const getNSSDynamicInstallInfo = ({ logger }) => {
|
|
30
27
|
return {
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
isInstallable: true,
|
|
29
|
+
install: async () => {
|
|
33
30
|
const aptInstallCommand = `sudo apt install libnss3-tools`
|
|
34
31
|
logger.info(
|
|
35
32
|
`"libnss3-tools" is not installed, trying to install "libnss3-tools"`,
|
|
36
33
|
)
|
|
37
|
-
logger.info(`${
|
|
34
|
+
logger.info(`${UNICODE.COMMAND} ${aptInstallCommand}`)
|
|
38
35
|
await exec(aptInstallCommand)
|
|
39
36
|
},
|
|
40
37
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync } from "node:fs"
|
|
2
|
+
import { UNICODE } from "@jsenv/log"
|
|
2
3
|
|
|
3
|
-
import { okSign, infoSign } from "@jsenv/https-local/src/internal/logs.js"
|
|
4
4
|
import { memoize } from "@jsenv/https-local/src/internal/memoize.js"
|
|
5
5
|
|
|
6
6
|
const REASON_CHROME_NOT_DETECTED = `Chrome not detected`
|
|
@@ -25,10 +25,10 @@ const detectChrome = memoize(({ logger }) => {
|
|
|
25
25
|
const chromeDetected = existsSync("/Applications/Google Chrome.app")
|
|
26
26
|
|
|
27
27
|
if (chromeDetected) {
|
|
28
|
-
logger.debug(`${
|
|
28
|
+
logger.debug(`${UNICODE.OK} Chrome detected`)
|
|
29
29
|
return true
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
logger.debug(`${
|
|
32
|
+
logger.debug(`${UNICODE.INFO} Chrome not detected`)
|
|
33
33
|
return false
|
|
34
34
|
})
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { existsSync } from "node:fs"
|
|
2
2
|
import { execSync } from "node:child_process"
|
|
3
3
|
import { resolveUrl, assertAndNormalizeDirectoryUrl } from "@jsenv/filesystem"
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
okSign,
|
|
7
|
-
infoSign,
|
|
8
|
-
warningSign,
|
|
9
|
-
} from "@jsenv/https-local/src/internal/logs.js"
|
|
4
|
+
import { UNICODE } from "@jsenv/log"
|
|
10
5
|
|
|
11
6
|
import { executeTrustQueryOnBrowserNSSDB } from "../nssdb_browser.js"
|
|
12
7
|
import {
|
|
@@ -45,11 +40,11 @@ export const executeTrustQueryOnFirefox = ({
|
|
|
45
40
|
const firefoxDetected = existsSync("/Applications/Firefox.app")
|
|
46
41
|
|
|
47
42
|
if (firefoxDetected) {
|
|
48
|
-
logger.debug(`${
|
|
43
|
+
logger.debug(`${UNICODE.OK} firefox detected`)
|
|
49
44
|
return true
|
|
50
45
|
}
|
|
51
46
|
|
|
52
|
-
logger.debug(`${
|
|
47
|
+
logger.debug(`${UNICODE.INFO} firefox not detected`)
|
|
53
48
|
return false
|
|
54
49
|
},
|
|
55
50
|
browserNSSDBDirectoryUrl: resolveUrl(
|
|
@@ -62,14 +57,14 @@ export const executeTrustQueryOnFirefox = ({
|
|
|
62
57
|
}
|
|
63
58
|
|
|
64
59
|
logger.warn(
|
|
65
|
-
`${
|
|
60
|
+
`${UNICODE.WARNING} waiting for you to close firefox before resuming...`,
|
|
66
61
|
)
|
|
67
62
|
const next = async () => {
|
|
68
63
|
await new Promise((resolve) => setTimeout(resolve, 50))
|
|
69
64
|
if (isFirefoxOpen()) {
|
|
70
65
|
await next()
|
|
71
66
|
} else {
|
|
72
|
-
logger.info(`${
|
|
67
|
+
logger.info(`${UNICODE.OK} firefox closed, resuming`)
|
|
73
68
|
// wait 50ms more to ensure firefox has time to cleanup
|
|
74
69
|
// othrwise sometimes there is an SEC_ERROR_REUSED_ISSUER_AND_SERIAL error
|
|
75
70
|
// because we updated nss database file while firefox is not fully closed
|
|
@@ -3,12 +3,7 @@
|
|
|
3
3
|
import { urlToFileSystemPath } from "@jsenv/filesystem"
|
|
4
4
|
import { createDetailedMessage } from "@jsenv/logger"
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
commandSign,
|
|
8
|
-
okSign,
|
|
9
|
-
infoSign,
|
|
10
|
-
failureSign,
|
|
11
|
-
} from "@jsenv/https-local/src/internal/logs.js"
|
|
6
|
+
import { UNICODE } from "@jsenv/log"
|
|
12
7
|
import { exec } from "@jsenv/https-local/src/internal/exec.js"
|
|
13
8
|
import { searchCertificateInCommandOutput } from "@jsenv/https-local/src/internal/search_certificate_in_command_output.js"
|
|
14
9
|
import {
|
|
@@ -41,7 +36,7 @@ export const executeTrustQueryOnMacKeychain = async ({
|
|
|
41
36
|
verb,
|
|
42
37
|
}) => {
|
|
43
38
|
if (verb === VERB_CHECK_TRUST && certificateIsNew) {
|
|
44
|
-
logger.info(`${
|
|
39
|
+
logger.info(`${UNICODE.INFO} You should add certificate to mac keychain`)
|
|
45
40
|
return {
|
|
46
41
|
status: "not_trusted",
|
|
47
42
|
reason: REASON_NEW_AND_TRY_TO_TRUST_DISABLED,
|
|
@@ -51,7 +46,7 @@ export const executeTrustQueryOnMacKeychain = async ({
|
|
|
51
46
|
logger.info(`Check if certificate is in mac keychain...`)
|
|
52
47
|
// https://ss64.com/osx/security-find-cert.html
|
|
53
48
|
const findCertificateCommand = `security find-certificate -a -p ${systemKeychainPath}`
|
|
54
|
-
logger.debug(`${
|
|
49
|
+
logger.debug(`${UNICODE.COMMAND} ${findCertificateCommand}`)
|
|
55
50
|
const findCertificateCommandOutput = await exec(findCertificateCommand)
|
|
56
51
|
const certificateFoundInCommandOutput = searchCertificateInCommandOutput(
|
|
57
52
|
findCertificateCommandOutput,
|
|
@@ -59,7 +54,7 @@ export const executeTrustQueryOnMacKeychain = async ({
|
|
|
59
54
|
)
|
|
60
55
|
|
|
61
56
|
if (!certificateFoundInCommandOutput) {
|
|
62
|
-
logger.info(`${
|
|
57
|
+
logger.info(`${UNICODE.INFO} certificate not found in mac keychain`)
|
|
63
58
|
if (verb === VERB_CHECK_TRUST || verb === VERB_REMOVE_TRUST) {
|
|
64
59
|
return {
|
|
65
60
|
status: "not_trusted",
|
|
@@ -71,10 +66,10 @@ export const executeTrustQueryOnMacKeychain = async ({
|
|
|
71
66
|
// https://ss64.com/osx/security-cert.html
|
|
72
67
|
const addTrustedCertCommand = `sudo security add-trusted-cert -d -r trustRoot -k ${systemKeychainPath} "${certificateFilePath}"`
|
|
73
68
|
logger.info(`Adding certificate to mac keychain...`)
|
|
74
|
-
logger.info(`${
|
|
69
|
+
logger.info(`${UNICODE.COMMAND} ${addTrustedCertCommand}`)
|
|
75
70
|
try {
|
|
76
71
|
await exec(addTrustedCertCommand)
|
|
77
|
-
logger.info(`${
|
|
72
|
+
logger.info(`${UNICODE.OK} certificate added to mac keychain`)
|
|
78
73
|
return {
|
|
79
74
|
status: "trusted",
|
|
80
75
|
reason: REASON_ADD_TO_KEYCHAIN_COMMAND_COMPLETED,
|
|
@@ -82,7 +77,7 @@ export const executeTrustQueryOnMacKeychain = async ({
|
|
|
82
77
|
} catch (e) {
|
|
83
78
|
logger.error(
|
|
84
79
|
createDetailedMessage(
|
|
85
|
-
`${
|
|
80
|
+
`${UNICODE.FAILURE} failed to add certificate to mac keychain`,
|
|
86
81
|
{
|
|
87
82
|
"error stack": e.stack,
|
|
88
83
|
"certificate file": certificateFilePath,
|
|
@@ -100,7 +95,7 @@ export const executeTrustQueryOnMacKeychain = async ({
|
|
|
100
95
|
// people can still manually untrust the root cert
|
|
101
96
|
// but they shouldn't and I couldn't find an API to know if the cert is trusted or not
|
|
102
97
|
// just if it's in the keychain
|
|
103
|
-
logger.info(`${
|
|
98
|
+
logger.info(`${UNICODE.OK} certificate found in mac keychain`)
|
|
104
99
|
if (verb === VERB_CHECK_TRUST || verb === VERB_ADD_TRUST) {
|
|
105
100
|
return {
|
|
106
101
|
status: "trusted",
|
|
@@ -111,10 +106,10 @@ export const executeTrustQueryOnMacKeychain = async ({
|
|
|
111
106
|
// https://ss64.com/osx/security-delete-cert.html
|
|
112
107
|
const removeTrustedCertCommand = `sudo security delete-certificate -c "${certificateCommonName}"`
|
|
113
108
|
logger.info(`Removing certificate from mac keychain...`)
|
|
114
|
-
logger.info(`${
|
|
109
|
+
logger.info(`${UNICODE.COMMAND} ${removeTrustedCertCommand}`)
|
|
115
110
|
try {
|
|
116
111
|
await exec(removeTrustedCertCommand)
|
|
117
|
-
logger.info(`${
|
|
112
|
+
logger.info(`${UNICODE.OK} certificate removed from mac keychain`)
|
|
118
113
|
return {
|
|
119
114
|
status: "not_trusted",
|
|
120
115
|
reason: REASON_REMOVE_FROM_KEYCHAIN_COMMAND_COMPLETED,
|
|
@@ -122,7 +117,7 @@ export const executeTrustQueryOnMacKeychain = async ({
|
|
|
122
117
|
} catch (e) {
|
|
123
118
|
logger.error(
|
|
124
119
|
createDetailedMessage(
|
|
125
|
-
`${
|
|
120
|
+
`${UNICODE.FAILURE} failed to remove certificate from mac keychain`,
|
|
126
121
|
{
|
|
127
122
|
"error stack": e.stack,
|
|
128
123
|
"certificate file url": certificateFileUrl,
|
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
resolveUrl,
|
|
4
4
|
urlToFileSystemPath,
|
|
5
5
|
} from "@jsenv/filesystem"
|
|
6
|
+
import { UNICODE } from "@jsenv/log"
|
|
6
7
|
|
|
7
8
|
import { memoize } from "@jsenv/https-local/src/internal/memoize.js"
|
|
8
9
|
import { exec } from "@jsenv/https-local/src/internal/exec.js"
|
|
9
|
-
import { infoSign, okSign } from "@jsenv/https-local/src/internal/logs.js"
|
|
10
10
|
import { commandExists } from "@jsenv/https-local/src/internal/command.js"
|
|
11
11
|
|
|
12
12
|
export const nssCommandName = "nss"
|
|
@@ -17,10 +17,10 @@ export const detectIfNSSIsInstalled = async ({ logger }) => {
|
|
|
17
17
|
|
|
18
18
|
try {
|
|
19
19
|
await exec(brewListCommand)
|
|
20
|
-
logger.debug(`${
|
|
20
|
+
logger.debug(`${UNICODE.OK} nss is installed`)
|
|
21
21
|
return true
|
|
22
22
|
} catch (e) {
|
|
23
|
-
logger.debug(`${
|
|
23
|
+
logger.debug(`${UNICODE.INFO} nss not installed`)
|
|
24
24
|
return false
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -38,15 +38,15 @@ export const getCertutilBinPath = memoize(async () => {
|
|
|
38
38
|
|
|
39
39
|
export const getNSSDynamicInstallInfo = () => {
|
|
40
40
|
return {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
isInstallable: commandExists("brew"),
|
|
42
|
+
notInstallableReason: `"brew" is not available`,
|
|
43
|
+
suggestion: `install "brew" on this mac`,
|
|
44
|
+
install: async ({ logger }) => {
|
|
45
45
|
const brewInstallCommand = `brew install nss`
|
|
46
46
|
logger.info(
|
|
47
47
|
`"nss" is not installed, trying to install "nss" via Homebrew`,
|
|
48
48
|
)
|
|
49
|
-
logger.info(
|
|
49
|
+
logger.info(`${UNICODE.COMMAND} ${brewInstallCommand}`)
|
|
50
50
|
await exec(brewInstallCommand)
|
|
51
51
|
},
|
|
52
52
|
}
|
|
@@ -12,14 +12,8 @@ import {
|
|
|
12
12
|
urlToFilename,
|
|
13
13
|
urlToFileSystemPath,
|
|
14
14
|
} from "@jsenv/filesystem"
|
|
15
|
+
import { UNICODE } from "@jsenv/log"
|
|
15
16
|
|
|
16
|
-
import {
|
|
17
|
-
commandSign,
|
|
18
|
-
okSign,
|
|
19
|
-
infoSign,
|
|
20
|
-
warningSign,
|
|
21
|
-
failureSign,
|
|
22
|
-
} from "@jsenv/https-local/src/internal/logs.js"
|
|
23
17
|
import { exec } from "@jsenv/https-local/src/internal/exec.js"
|
|
24
18
|
import { searchCertificateInCommandOutput } from "@jsenv/https-local/src/internal/search_certificate_in_command_output.js"
|
|
25
19
|
import { VERB_CHECK_TRUST, VERB_ADD_TRUST } from "./trust_query.js"
|
|
@@ -52,7 +46,7 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
52
46
|
}
|
|
53
47
|
|
|
54
48
|
if (verb === VERB_CHECK_TRUST && certificateIsNew) {
|
|
55
|
-
logger.info(`${
|
|
49
|
+
logger.info(`${UNICODE.INFO} You should add certificate to ${browserName}`)
|
|
56
50
|
return {
|
|
57
51
|
status: "not_trusted",
|
|
58
52
|
reason: "certificate is new and tryToTrust is disabled",
|
|
@@ -61,22 +55,18 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
61
55
|
|
|
62
56
|
logger.info(`Check if certificate is in ${browserName}...`)
|
|
63
57
|
const nssIsInstalled = await detectIfNSSIsInstalled({ logger })
|
|
64
|
-
const cannotCheckMessage = `${
|
|
58
|
+
const cannotCheckMessage = `${UNICODE.FAILURE} cannot check if certificate is in ${browserName}`
|
|
65
59
|
if (!nssIsInstalled) {
|
|
66
60
|
if (verb === VERB_ADD_TRUST) {
|
|
67
|
-
const {
|
|
68
|
-
|
|
69
|
-
nssNotInstallableReason,
|
|
70
|
-
nssInstallFixSuggestion,
|
|
71
|
-
nssInstall,
|
|
72
|
-
} = await getNSSDynamicInstallInfo({ logger })
|
|
73
|
-
if (!nssIsInstallable) {
|
|
61
|
+
const nssDynamicInstallInfo = await getNSSDynamicInstallInfo({ logger })
|
|
62
|
+
if (!nssDynamicInstallInfo.isInstallable) {
|
|
74
63
|
const reason = `"${nssCommandName}" is not installed and not cannot be installed`
|
|
75
64
|
logger.warn(
|
|
76
65
|
createDetailedMessage(cannotCheckMessage, {
|
|
77
66
|
reason,
|
|
78
|
-
"reason it cannot be installed":
|
|
79
|
-
|
|
67
|
+
"reason it cannot be installed":
|
|
68
|
+
nssDynamicInstallInfo.notInstallableReason,
|
|
69
|
+
"suggested solution": nssDynamicInstallInfo.suggestion,
|
|
80
70
|
}),
|
|
81
71
|
)
|
|
82
72
|
return {
|
|
@@ -100,7 +90,7 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
100
90
|
}
|
|
101
91
|
|
|
102
92
|
try {
|
|
103
|
-
await
|
|
93
|
+
await nssDynamicInstallInfo.install({ logger })
|
|
104
94
|
} catch (e) {
|
|
105
95
|
logger.error(
|
|
106
96
|
createDetailedMessage(cannotCheckMessage, {
|
|
@@ -148,7 +138,7 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
148
138
|
const directoryArg = getDirectoryArgFromNSSDBFileUrl(NSSDBFileUrl)
|
|
149
139
|
const certutilListCommand = `${certutilBinPath} -L -a -d ${directoryArg} -n "${certificateCommonName}"`
|
|
150
140
|
logger.debug(`Checking if certificate is in nss database...`)
|
|
151
|
-
logger.debug(`${
|
|
141
|
+
logger.debug(`${UNICODE.COMMAND} ${certutilListCommand}`)
|
|
152
142
|
try {
|
|
153
143
|
const output = await execCertutilCommmand(certutilListCommand)
|
|
154
144
|
const isInDatabase = searchCertificateInCommandOutput(output, certificate)
|
|
@@ -168,18 +158,18 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
168
158
|
const directoryArg = getDirectoryArgFromNSSDBFileUrl(NSSDBFileUrl)
|
|
169
159
|
const certutilAddCommand = `${certutilBinPath} -A -d ${directoryArg} -t C,, -i "${certificateFilePath}" -n "${certificateCommonName}"`
|
|
170
160
|
logger.debug(`Adding certificate to nss database...`)
|
|
171
|
-
logger.debug(`${
|
|
161
|
+
logger.debug(`${UNICODE.COMMAND} ${certutilAddCommand}`)
|
|
172
162
|
await execCertutilCommmand(certutilAddCommand)
|
|
173
|
-
logger.debug(`${
|
|
163
|
+
logger.debug(`${UNICODE.OK} certificate added to nss database`)
|
|
174
164
|
}
|
|
175
165
|
|
|
176
166
|
const removeFromNSSDB = async ({ NSSDBFileUrl }) => {
|
|
177
167
|
const directoryArg = getDirectoryArgFromNSSDBFileUrl(NSSDBFileUrl)
|
|
178
168
|
const certutilRemoveCommand = `${certutilBinPath} -D -d ${directoryArg} -t C,, -i "${certificateFilePath}" -n "${certificateCommonName}"`
|
|
179
169
|
logger.debug(`Removing certificate from nss database...`)
|
|
180
|
-
logger.debug(`${
|
|
170
|
+
logger.debug(`${UNICODE.COMMAND} ${certutilRemoveCommand}`)
|
|
181
171
|
await execCertutilCommmand(certutilRemoveCommand)
|
|
182
|
-
logger.debug(`${
|
|
172
|
+
logger.debug(`${UNICODE.OK} certificate removed from nss database`)
|
|
183
173
|
}
|
|
184
174
|
|
|
185
175
|
const missings = []
|
|
@@ -190,7 +180,7 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
190
180
|
const certificateStatus = await checkNSSDB({ NSSDBFileUrl })
|
|
191
181
|
|
|
192
182
|
if (certificateStatus === "missing") {
|
|
193
|
-
logger.debug(`${
|
|
183
|
+
logger.debug(`${UNICODE.INFO} certificate not found in nss database`)
|
|
194
184
|
missings.push(NSSDBFileUrl)
|
|
195
185
|
return
|
|
196
186
|
}
|
|
@@ -200,7 +190,7 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
200
190
|
return
|
|
201
191
|
}
|
|
202
192
|
|
|
203
|
-
logger.debug(`${
|
|
193
|
+
logger.debug(`${UNICODE.OK} certificate found in nss database`)
|
|
204
194
|
founds.push(NSSDBFileUrl)
|
|
205
195
|
}),
|
|
206
196
|
)
|
|
@@ -211,13 +201,13 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
211
201
|
|
|
212
202
|
if (verb === VERB_CHECK_TRUST) {
|
|
213
203
|
if (missingCount > 0 || outdatedCount > 0) {
|
|
214
|
-
logger.info(`${
|
|
204
|
+
logger.info(`${UNICODE.INFO} certificate not found in ${browserName}`)
|
|
215
205
|
return {
|
|
216
206
|
status: "not_trusted",
|
|
217
207
|
reason: `missing or outdated in ${browserName} nss database file`,
|
|
218
208
|
}
|
|
219
209
|
}
|
|
220
|
-
logger.info(`${
|
|
210
|
+
logger.info(`${UNICODE.OK} certificate found in ${browserName}`)
|
|
221
211
|
return {
|
|
222
212
|
status: "trusted",
|
|
223
213
|
reason: `found in ${browserName} nss database file`,
|
|
@@ -226,13 +216,13 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
226
216
|
|
|
227
217
|
if (verb === VERB_ADD_TRUST) {
|
|
228
218
|
if (missingCount === 0 && outdatedCount === 0) {
|
|
229
|
-
logger.info(`${
|
|
219
|
+
logger.info(`${UNICODE.OK} certificate found in ${browserName}`)
|
|
230
220
|
return {
|
|
231
221
|
status: "trusted",
|
|
232
222
|
reason: `found in all ${browserName} nss database file`,
|
|
233
223
|
}
|
|
234
224
|
}
|
|
235
|
-
logger.info(`${
|
|
225
|
+
logger.info(`${UNICODE.INFO} certificate not found in ${browserName}`)
|
|
236
226
|
logger.info(`Adding certificate to ${browserName}...`)
|
|
237
227
|
await getBrowserClosedPromise()
|
|
238
228
|
await Promise.all(
|
|
@@ -246,7 +236,7 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
246
236
|
await addToNSSDB({ NSSDBFileUrl: outdated })
|
|
247
237
|
}),
|
|
248
238
|
)
|
|
249
|
-
logger.info(`${
|
|
239
|
+
logger.info(`${UNICODE.OK} certificate added to ${browserName}`)
|
|
250
240
|
return {
|
|
251
241
|
status: "trusted",
|
|
252
242
|
reason: `added to ${browserName} nss database file`,
|
|
@@ -254,13 +244,13 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
254
244
|
}
|
|
255
245
|
|
|
256
246
|
if (outdatedCount === 0 && foundCount === 0) {
|
|
257
|
-
logger.info(`${
|
|
247
|
+
logger.info(`${UNICODE.INFO} certificate not found in ${browserName}`)
|
|
258
248
|
return {
|
|
259
249
|
status: "not_trusted",
|
|
260
250
|
reason: `not found in ${browserName} nss database file`,
|
|
261
251
|
}
|
|
262
252
|
}
|
|
263
|
-
logger.info(`${
|
|
253
|
+
logger.info(`${UNICODE.INFO} found certificate in ${browserName}`)
|
|
264
254
|
logger.info(`Removing certificate from ${browserName}...`)
|
|
265
255
|
await getBrowserClosedPromise()
|
|
266
256
|
await Promise.all(
|
|
@@ -273,7 +263,7 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
273
263
|
await removeFromNSSDB({ NSSDBFileUrl: found })
|
|
274
264
|
}),
|
|
275
265
|
)
|
|
276
|
-
logger.info(`${
|
|
266
|
+
logger.info(`${UNICODE.OK} certificate removed from ${browserName}`)
|
|
277
267
|
return {
|
|
278
268
|
status: "not_trusted",
|
|
279
269
|
reason: `removed from ${browserName} nss database file`,
|
|
@@ -302,7 +292,7 @@ const findNSSDBFiles = async ({ logger, NSSDBDirectoryUrl }) => {
|
|
|
302
292
|
const NSSDBDirectoryExists = existsSync(NSSDBDirectoryPath)
|
|
303
293
|
if (!NSSDBDirectoryExists) {
|
|
304
294
|
logger.info(
|
|
305
|
-
`${
|
|
295
|
+
`${UNICODE.INFO} nss database directory not found on filesystem at ${NSSDBDirectoryPath}`,
|
|
306
296
|
)
|
|
307
297
|
NSSDirectoryCache[NSSDBDirectoryUrl] = []
|
|
308
298
|
return []
|
|
@@ -324,14 +314,14 @@ const findNSSDBFiles = async ({ logger, NSSDBDirectoryUrl }) => {
|
|
|
324
314
|
const fileCount = NSSDBFiles.length
|
|
325
315
|
if (fileCount === 0) {
|
|
326
316
|
logger.warn(
|
|
327
|
-
`${
|
|
317
|
+
`${UNICODE.WARNING} could not find nss database file in ${NSSDBDirectoryUrl}`,
|
|
328
318
|
)
|
|
329
319
|
NSSDirectoryCache[NSSDBDirectoryUrl] = []
|
|
330
320
|
return []
|
|
331
321
|
}
|
|
332
322
|
|
|
333
323
|
logger.debug(
|
|
334
|
-
`${
|
|
324
|
+
`${UNICODE.OK} found ${fileCount} nss database file in ${NSSDBDirectoryUrl}`,
|
|
335
325
|
)
|
|
336
326
|
const files = NSSDBFiles.map((file) => {
|
|
337
327
|
return resolveUrl(file.relativeUrl, NSSDBDirectoryUrl)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { UNICODE } from "@jsenv/log"
|
|
2
2
|
|
|
3
3
|
const platformTrustInfo = {
|
|
4
4
|
status: "unknown",
|
|
@@ -7,7 +7,7 @@ const platformTrustInfo = {
|
|
|
7
7
|
|
|
8
8
|
export const executeTrustQuery = ({ logger }) => {
|
|
9
9
|
logger.warn(
|
|
10
|
-
`${
|
|
10
|
+
`${UNICODE.WARNING} platform not supported, cannot execute trust query`,
|
|
11
11
|
)
|
|
12
12
|
return {
|
|
13
13
|
platform: platformTrustInfo,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire } from "node:module"
|
|
2
2
|
import { existsSync } from "node:fs"
|
|
3
|
+
import { UNICODE } from "@jsenv/log"
|
|
3
4
|
|
|
4
|
-
import { okSign, infoSign } from "@jsenv/https-local/src/internal/logs.js"
|
|
5
5
|
import { memoize } from "@jsenv/https-local/src/internal/memoize.js"
|
|
6
6
|
|
|
7
7
|
const require = createRequire(import.meta.url)
|
|
@@ -30,7 +30,7 @@ const detectChrome = memoize(({ logger }) => {
|
|
|
30
30
|
logger.debug(`Detecting Chrome...`)
|
|
31
31
|
|
|
32
32
|
if (process.env.CHROME_BIN && which.sync(process.env.CHROME_BIN)) {
|
|
33
|
-
logger.debug(`${
|
|
33
|
+
logger.debug(`${UNICODE.OK} Chrome detected`)
|
|
34
34
|
return true
|
|
35
35
|
}
|
|
36
36
|
|
|
@@ -53,10 +53,10 @@ const detectChrome = memoize(({ logger }) => {
|
|
|
53
53
|
},
|
|
54
54
|
)
|
|
55
55
|
if (someExecutableFound) {
|
|
56
|
-
logger.debug(`${
|
|
56
|
+
logger.debug(`${UNICODE.OK} Chrome detected`)
|
|
57
57
|
return true
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
logger.debug(`${
|
|
60
|
+
logger.debug(`${UNICODE.OK} Chrome detected`)
|
|
61
61
|
return false
|
|
62
62
|
})
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
import { createRequire } from "node:module"
|
|
7
7
|
import { existsSync } from "node:fs"
|
|
8
|
+
import { UNICODE } from "@jsenv/log"
|
|
8
9
|
|
|
9
|
-
import { okSign, infoSign } from "@jsenv/https-local/src/internal/logs.js"
|
|
10
10
|
import { memoize } from "@jsenv/https-local/src/internal/memoize.js"
|
|
11
11
|
|
|
12
12
|
const require = createRequire(import.meta.url)
|
|
@@ -26,7 +26,7 @@ export const executeTrustQueryOnFirefox = ({ logger, certificateIsNew }) => {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
if (certificateIsNew) {
|
|
29
|
-
logger.info(`${
|
|
29
|
+
logger.info(`${UNICODE.INFO} You should add certificate to firefox`)
|
|
30
30
|
return {
|
|
31
31
|
status: "not_trusted",
|
|
32
32
|
reason: "certificate is new and tryToTrust is disabled",
|
|
@@ -35,7 +35,7 @@ export const executeTrustQueryOnFirefox = ({ logger, certificateIsNew }) => {
|
|
|
35
35
|
|
|
36
36
|
logger.info(`Check if certificate is in firefox...`)
|
|
37
37
|
logger.info(
|
|
38
|
-
`${
|
|
38
|
+
`${UNICODE.INFO} cannot check if certificate is in firefox (${REASON_NOT_IMPLEMENTED_ON_WINDOWS})`,
|
|
39
39
|
)
|
|
40
40
|
return {
|
|
41
41
|
status: "unknown",
|
|
@@ -48,7 +48,7 @@ const detectFirefox = memoize(({ logger }) => {
|
|
|
48
48
|
logger.debug(`Detecting Firefox...`)
|
|
49
49
|
|
|
50
50
|
if (process.env.FIREFOX_BIN && which.sync(process.env.FIREFOX_BIN)) {
|
|
51
|
-
logger.debug(`${
|
|
51
|
+
logger.debug(`${UNICODE.OK} Firefox detected`)
|
|
52
52
|
return true
|
|
53
53
|
}
|
|
54
54
|
|
|
@@ -71,10 +71,10 @@ const detectFirefox = memoize(({ logger }) => {
|
|
|
71
71
|
},
|
|
72
72
|
)
|
|
73
73
|
if (someExecutableFound) {
|
|
74
|
-
logger.debug(`${
|
|
74
|
+
logger.debug(`${UNICODE.OK} Firefox detected`)
|
|
75
75
|
return true
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
logger.debug(`${
|
|
78
|
+
logger.debug(`${UNICODE.INFO} Firefox detected`)
|
|
79
79
|
return false
|
|
80
80
|
})
|
|
@@ -5,13 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
import { createDetailedMessage } from "@jsenv/logger"
|
|
7
7
|
import { urlToFileSystemPath } from "@jsenv/filesystem"
|
|
8
|
+
import { UNICODE } from "@jsenv/log"
|
|
8
9
|
|
|
9
|
-
import {
|
|
10
|
-
commandSign,
|
|
11
|
-
okSign,
|
|
12
|
-
infoSign,
|
|
13
|
-
failureSign,
|
|
14
|
-
} from "@jsenv/https-local/src/internal/logs.js"
|
|
15
10
|
import { exec } from "@jsenv/https-local/src/internal/exec.js"
|
|
16
11
|
import {
|
|
17
12
|
VERB_CHECK_TRUST,
|
|
@@ -41,7 +36,7 @@ export const executeTrustQueryOnWindows = async ({
|
|
|
41
36
|
verb,
|
|
42
37
|
}) => {
|
|
43
38
|
if (verb === VERB_CHECK_TRUST && certificateIsNew) {
|
|
44
|
-
logger.info(`${
|
|
39
|
+
logger.info(`${UNICODE.INFO} You should add certificate to windows`)
|
|
45
40
|
return {
|
|
46
41
|
status: "not_trusted",
|
|
47
42
|
reason: REASON_NEW_AND_TRY_TO_TRUST_DISABLED,
|
|
@@ -52,7 +47,7 @@ export const executeTrustQueryOnWindows = async ({
|
|
|
52
47
|
// https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/certutil#-viewstore
|
|
53
48
|
// TODO: check if -viewstore works better than -store
|
|
54
49
|
const certutilListCommand = `certutil -store -user root`
|
|
55
|
-
logger.debug(`${
|
|
50
|
+
logger.debug(`${UNICODE.COMMAND} ${certutilListCommand}`)
|
|
56
51
|
const certutilListCommandOutput = await exec(certutilListCommand)
|
|
57
52
|
const certificateFilePath = urlToFileSystemPath(certificateFileUrl)
|
|
58
53
|
|
|
@@ -62,7 +57,7 @@ export const executeTrustQueryOnWindows = async ({
|
|
|
62
57
|
certificateCommonName,
|
|
63
58
|
)
|
|
64
59
|
if (!certificateInStore) {
|
|
65
|
-
logger.info(`${
|
|
60
|
+
logger.info(`${UNICODE.INFO} certificate not found in windows`)
|
|
66
61
|
if (verb === VERB_CHECK_TRUST || verb === VERB_REMOVE_TRUST) {
|
|
67
62
|
return {
|
|
68
63
|
status: "not_trusted",
|
|
@@ -73,10 +68,10 @@ export const executeTrustQueryOnWindows = async ({
|
|
|
73
68
|
// https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/certutil#-addstore
|
|
74
69
|
const certutilAddCommand = `certutil -addstore -user root ${certificateFilePath}`
|
|
75
70
|
logger.info(`Adding certificate to windows...`)
|
|
76
|
-
logger.info(`${
|
|
71
|
+
logger.info(`${UNICODE.COMMAND} ${certutilAddCommand}`)
|
|
77
72
|
try {
|
|
78
73
|
await exec(certutilAddCommand)
|
|
79
|
-
logger.info(`${
|
|
74
|
+
logger.info(`${UNICODE.OK} certificate added to windows`)
|
|
80
75
|
return {
|
|
81
76
|
status: "trusted",
|
|
82
77
|
reason: REASON_ADD_COMMAND_COMPLETED,
|
|
@@ -84,7 +79,7 @@ export const executeTrustQueryOnWindows = async ({
|
|
|
84
79
|
} catch (e) {
|
|
85
80
|
logger.error(
|
|
86
81
|
createDetailedMessage(
|
|
87
|
-
`${
|
|
82
|
+
`${UNICODE.FAILURE} Failed to add certificate to windows`,
|
|
88
83
|
{
|
|
89
84
|
"error stack": e.stack,
|
|
90
85
|
"certificate file": certificateFilePath,
|
|
@@ -98,7 +93,7 @@ export const executeTrustQueryOnWindows = async ({
|
|
|
98
93
|
}
|
|
99
94
|
}
|
|
100
95
|
|
|
101
|
-
logger.info(`${
|
|
96
|
+
logger.info(`${UNICODE.OK} certificate found in windows`)
|
|
102
97
|
if (verb === VERB_CHECK_TRUST || verb === VERB_ADD_TRUST) {
|
|
103
98
|
return {
|
|
104
99
|
status: "trusted",
|
|
@@ -109,10 +104,10 @@ export const executeTrustQueryOnWindows = async ({
|
|
|
109
104
|
// https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/certutil#-delstore
|
|
110
105
|
const certutilRemoveCommand = `certutil -delstore -user root "${certificateCommonName}"`
|
|
111
106
|
logger.info(`Removing certificate from windows...`)
|
|
112
|
-
logger.info(`${
|
|
107
|
+
logger.info(`${UNICODE.COMMAND} ${certutilRemoveCommand}`)
|
|
113
108
|
try {
|
|
114
109
|
await exec(certutilRemoveCommand)
|
|
115
|
-
logger.info(`${
|
|
110
|
+
logger.info(`${UNICODE.OK} certificate removed from windows`)
|
|
116
111
|
return {
|
|
117
112
|
status: "not_trusted",
|
|
118
113
|
reason: REASON_DELETE_COMMAND_COMPLETED,
|
|
@@ -120,7 +115,7 @@ export const executeTrustQueryOnWindows = async ({
|
|
|
120
115
|
} catch (e) {
|
|
121
116
|
logger.error(
|
|
122
117
|
createDetailedMessage(
|
|
123
|
-
`${
|
|
118
|
+
`${UNICODE.FAILURE} failed to remove certificate from windows`,
|
|
124
119
|
{
|
|
125
120
|
"error stack": e.stack,
|
|
126
121
|
"certificate file": certificateFilePath,
|
package/src/internal/logs.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import isUnicodeSupported from "is-unicode-supported"
|
|
2
|
-
import { createSupportsColor } from "supports-color"
|
|
3
|
-
|
|
4
|
-
const canUseUnicode = isUnicodeSupported()
|
|
5
|
-
const processSupportsBasicColor = createSupportsColor(process.stdout).hasBasic
|
|
6
|
-
|
|
7
|
-
export const ANSI_RED = "\x1b[31m"
|
|
8
|
-
export const ANSI_GREEN = "\x1b[32m"
|
|
9
|
-
export const ANSI_YELLOW = "\x1b[33m"
|
|
10
|
-
export const ANSI_BLUE = "\x1b[34m"
|
|
11
|
-
export const ANSI_MAGENTA = "\x1b[35m"
|
|
12
|
-
export const ANSI_GREY = "\x1b[39m"
|
|
13
|
-
export const ANSI_RESET = "\x1b[0m"
|
|
14
|
-
|
|
15
|
-
export const setANSIColor = processSupportsBasicColor
|
|
16
|
-
? (text, ANSI_COLOR) => `${ANSI_COLOR}${text}${ANSI_RESET}`
|
|
17
|
-
: (text) => text
|
|
18
|
-
|
|
19
|
-
export const commandSign = setANSIColor(canUseUnicode ? `❯` : `>`, ANSI_GREY) // ANSI_MAGENTA)
|
|
20
|
-
export const okSign = setANSIColor(canUseUnicode ? `✔` : `√`, ANSI_GREEN)
|
|
21
|
-
export const failureSign = setANSIColor(canUseUnicode ? `✖` : `×`, ANSI_RED)
|
|
22
|
-
export const infoSign = setANSIColor(canUseUnicode ? `ℹ` : `i`, ANSI_BLUE)
|
|
23
|
-
export const warningSign = setANSIColor(canUseUnicode ? `⚠` : `‼`, ANSI_YELLOW)
|