@jsenv/https-local 1.0.7 → 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 +13 -14
- package/src/certificate_authority.js +15 -13
- 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 +6 -9
- 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 +4 -4
- package/src/internal/nssdb_browser.js +21 -27
- 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
67
|
"@jsenv/package-publish": "1.7.2",
|
|
69
|
-
"@jsenv/performance-impact": "2.2.
|
|
70
|
-
"eslint": "8.
|
|
71
|
-
"eslint-plugin-import": "2.
|
|
72
|
-
"playwright": "1.
|
|
73
|
-
"prettier": "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,7 +1,7 @@
|
|
|
1
|
-
import { readFile, writeFile,
|
|
1
|
+
import { readFile, writeFile, removeEntry } from "@jsenv/filesystem"
|
|
2
2
|
import { createLogger, createDetailedMessage } from "@jsenv/logger"
|
|
3
|
+
import { UNICODE } from "@jsenv/log"
|
|
3
4
|
|
|
4
|
-
import { infoSign, okSign } from "./internal/logs.js"
|
|
5
5
|
import { getAuthorityFileInfos } from "./internal/authority_file_infos.js"
|
|
6
6
|
import { attributeDescriptionFromAttributeArray } from "./internal/certificate_data_converter.js"
|
|
7
7
|
import {
|
|
@@ -95,7 +95,7 @@ export const installCertificateAuthority = async ({
|
|
|
95
95
|
)
|
|
96
96
|
|
|
97
97
|
logger.info(
|
|
98
|
-
`${
|
|
98
|
+
`${UNICODE.OK} authority root certificate written at ${rootCertificateFileInfo.path}`,
|
|
99
99
|
)
|
|
100
100
|
return {
|
|
101
101
|
rootCertificateForgeObject,
|
|
@@ -152,7 +152,7 @@ export const installCertificateAuthority = async ({
|
|
|
152
152
|
`Authority root certificate is not on filesystem at ${rootCertificateFileInfo.path}`,
|
|
153
153
|
)
|
|
154
154
|
logger.info(
|
|
155
|
-
`${
|
|
155
|
+
`${UNICODE.INFO} authority root certificate not found in filesystem`,
|
|
156
156
|
)
|
|
157
157
|
return generate()
|
|
158
158
|
}
|
|
@@ -161,14 +161,14 @@ export const installCertificateAuthority = async ({
|
|
|
161
161
|
`Authority root certificate private key is not on filesystem at ${rootCertificatePrivateKeyFileInfo.path}`,
|
|
162
162
|
)
|
|
163
163
|
logger.info(
|
|
164
|
-
`${
|
|
164
|
+
`${UNICODE.INFO} authority root certificate not found in filesystem`,
|
|
165
165
|
)
|
|
166
166
|
return generate()
|
|
167
167
|
}
|
|
168
168
|
logger.debug(
|
|
169
169
|
`found authority root certificate files at ${rootCertificateFileInfo.path} and ${rootCertificatePrivateKeyFileInfo.path}`,
|
|
170
170
|
)
|
|
171
|
-
logger.info(`${
|
|
171
|
+
logger.info(`${UNICODE.OK} authority root certificate found in filesystem`)
|
|
172
172
|
|
|
173
173
|
const rootCertificate = await readFile(rootCertificateFileInfo.path, {
|
|
174
174
|
as: "string",
|
|
@@ -184,7 +184,7 @@ export const installCertificateAuthority = async ({
|
|
|
184
184
|
)
|
|
185
185
|
if (rootCertificateValidityRemainingMs < 0) {
|
|
186
186
|
logger.info(
|
|
187
|
-
`${
|
|
187
|
+
`${UNICODE.INFO} certificate expired ${formatTimeDelta(
|
|
188
188
|
rootCertificateValidityRemainingMs,
|
|
189
189
|
)}`,
|
|
190
190
|
)
|
|
@@ -194,14 +194,14 @@ export const installCertificateAuthority = async ({
|
|
|
194
194
|
rootCertificateValidityRemainingMs / rootCertificateValidityDurationInMs
|
|
195
195
|
if (rootCertificateValidityRemainingRatio < aboutToExpireRatio) {
|
|
196
196
|
logger.info(
|
|
197
|
-
`${
|
|
197
|
+
`${UNICODE.INFO} certificate will expire ${formatTimeDelta(
|
|
198
198
|
rootCertificateValidityRemainingMs,
|
|
199
199
|
)}`,
|
|
200
200
|
)
|
|
201
201
|
return regenerate()
|
|
202
202
|
}
|
|
203
203
|
logger.info(
|
|
204
|
-
`${
|
|
204
|
+
`${UNICODE.OK} certificate still valid for ${formatDuration(
|
|
205
205
|
rootCertificateValidityRemainingMs,
|
|
206
206
|
)}`,
|
|
207
207
|
)
|
|
@@ -217,11 +217,11 @@ export const installCertificateAuthority = async ({
|
|
|
217
217
|
if (rootCertificateDifferences.length) {
|
|
218
218
|
const paramNames = Object.keys(rootCertificateDifferences)
|
|
219
219
|
logger.info(
|
|
220
|
-
`${
|
|
220
|
+
`${UNICODE.INFO} certificate attributes are outdated: ${paramNames}`,
|
|
221
221
|
)
|
|
222
222
|
return regenerate()
|
|
223
223
|
}
|
|
224
|
-
logger.info(`${
|
|
224
|
+
logger.info(`${UNICODE.OK} certificate attributes are the same`)
|
|
225
225
|
|
|
226
226
|
const rootCertificatePrivateKey = await readFile(
|
|
227
227
|
rootCertificatePrivateKeyFileInfo.path,
|
|
@@ -346,10 +346,12 @@ export const uninstallCertificateAuthority = async ({
|
|
|
346
346
|
logger.info(`Removing certificate authority files...`)
|
|
347
347
|
await Promise.all(
|
|
348
348
|
filesToRemove.map(async (file) => {
|
|
349
|
-
await
|
|
349
|
+
await removeEntry(file)
|
|
350
350
|
}),
|
|
351
351
|
)
|
|
352
|
-
logger.info(
|
|
352
|
+
logger.info(
|
|
353
|
+
`${UNICODE.OK} certificate authority files removed from filesystem`,
|
|
354
|
+
)
|
|
353
355
|
}
|
|
354
356
|
}
|
|
355
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
|
|
|
@@ -34,7 +31,7 @@ export const getNSSDynamicInstallInfo = ({ logger }) => {
|
|
|
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
|
}
|
|
@@ -46,7 +46,7 @@ export const getNSSDynamicInstallInfo = () => {
|
|
|
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,7 +55,7 @@ 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
61
|
const nssDynamicInstallInfo = await getNSSDynamicInstallInfo({ logger })
|
|
@@ -144,7 +138,7 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
144
138
|
const directoryArg = getDirectoryArgFromNSSDBFileUrl(NSSDBFileUrl)
|
|
145
139
|
const certutilListCommand = `${certutilBinPath} -L -a -d ${directoryArg} -n "${certificateCommonName}"`
|
|
146
140
|
logger.debug(`Checking if certificate is in nss database...`)
|
|
147
|
-
logger.debug(`${
|
|
141
|
+
logger.debug(`${UNICODE.COMMAND} ${certutilListCommand}`)
|
|
148
142
|
try {
|
|
149
143
|
const output = await execCertutilCommmand(certutilListCommand)
|
|
150
144
|
const isInDatabase = searchCertificateInCommandOutput(output, certificate)
|
|
@@ -164,18 +158,18 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
164
158
|
const directoryArg = getDirectoryArgFromNSSDBFileUrl(NSSDBFileUrl)
|
|
165
159
|
const certutilAddCommand = `${certutilBinPath} -A -d ${directoryArg} -t C,, -i "${certificateFilePath}" -n "${certificateCommonName}"`
|
|
166
160
|
logger.debug(`Adding certificate to nss database...`)
|
|
167
|
-
logger.debug(`${
|
|
161
|
+
logger.debug(`${UNICODE.COMMAND} ${certutilAddCommand}`)
|
|
168
162
|
await execCertutilCommmand(certutilAddCommand)
|
|
169
|
-
logger.debug(`${
|
|
163
|
+
logger.debug(`${UNICODE.OK} certificate added to nss database`)
|
|
170
164
|
}
|
|
171
165
|
|
|
172
166
|
const removeFromNSSDB = async ({ NSSDBFileUrl }) => {
|
|
173
167
|
const directoryArg = getDirectoryArgFromNSSDBFileUrl(NSSDBFileUrl)
|
|
174
168
|
const certutilRemoveCommand = `${certutilBinPath} -D -d ${directoryArg} -t C,, -i "${certificateFilePath}" -n "${certificateCommonName}"`
|
|
175
169
|
logger.debug(`Removing certificate from nss database...`)
|
|
176
|
-
logger.debug(`${
|
|
170
|
+
logger.debug(`${UNICODE.COMMAND} ${certutilRemoveCommand}`)
|
|
177
171
|
await execCertutilCommmand(certutilRemoveCommand)
|
|
178
|
-
logger.debug(`${
|
|
172
|
+
logger.debug(`${UNICODE.OK} certificate removed from nss database`)
|
|
179
173
|
}
|
|
180
174
|
|
|
181
175
|
const missings = []
|
|
@@ -186,7 +180,7 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
186
180
|
const certificateStatus = await checkNSSDB({ NSSDBFileUrl })
|
|
187
181
|
|
|
188
182
|
if (certificateStatus === "missing") {
|
|
189
|
-
logger.debug(`${
|
|
183
|
+
logger.debug(`${UNICODE.INFO} certificate not found in nss database`)
|
|
190
184
|
missings.push(NSSDBFileUrl)
|
|
191
185
|
return
|
|
192
186
|
}
|
|
@@ -196,7 +190,7 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
196
190
|
return
|
|
197
191
|
}
|
|
198
192
|
|
|
199
|
-
logger.debug(`${
|
|
193
|
+
logger.debug(`${UNICODE.OK} certificate found in nss database`)
|
|
200
194
|
founds.push(NSSDBFileUrl)
|
|
201
195
|
}),
|
|
202
196
|
)
|
|
@@ -207,13 +201,13 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
207
201
|
|
|
208
202
|
if (verb === VERB_CHECK_TRUST) {
|
|
209
203
|
if (missingCount > 0 || outdatedCount > 0) {
|
|
210
|
-
logger.info(`${
|
|
204
|
+
logger.info(`${UNICODE.INFO} certificate not found in ${browserName}`)
|
|
211
205
|
return {
|
|
212
206
|
status: "not_trusted",
|
|
213
207
|
reason: `missing or outdated in ${browserName} nss database file`,
|
|
214
208
|
}
|
|
215
209
|
}
|
|
216
|
-
logger.info(`${
|
|
210
|
+
logger.info(`${UNICODE.OK} certificate found in ${browserName}`)
|
|
217
211
|
return {
|
|
218
212
|
status: "trusted",
|
|
219
213
|
reason: `found in ${browserName} nss database file`,
|
|
@@ -222,13 +216,13 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
222
216
|
|
|
223
217
|
if (verb === VERB_ADD_TRUST) {
|
|
224
218
|
if (missingCount === 0 && outdatedCount === 0) {
|
|
225
|
-
logger.info(`${
|
|
219
|
+
logger.info(`${UNICODE.OK} certificate found in ${browserName}`)
|
|
226
220
|
return {
|
|
227
221
|
status: "trusted",
|
|
228
222
|
reason: `found in all ${browserName} nss database file`,
|
|
229
223
|
}
|
|
230
224
|
}
|
|
231
|
-
logger.info(`${
|
|
225
|
+
logger.info(`${UNICODE.INFO} certificate not found in ${browserName}`)
|
|
232
226
|
logger.info(`Adding certificate to ${browserName}...`)
|
|
233
227
|
await getBrowserClosedPromise()
|
|
234
228
|
await Promise.all(
|
|
@@ -242,7 +236,7 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
242
236
|
await addToNSSDB({ NSSDBFileUrl: outdated })
|
|
243
237
|
}),
|
|
244
238
|
)
|
|
245
|
-
logger.info(`${
|
|
239
|
+
logger.info(`${UNICODE.OK} certificate added to ${browserName}`)
|
|
246
240
|
return {
|
|
247
241
|
status: "trusted",
|
|
248
242
|
reason: `added to ${browserName} nss database file`,
|
|
@@ -250,13 +244,13 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
250
244
|
}
|
|
251
245
|
|
|
252
246
|
if (outdatedCount === 0 && foundCount === 0) {
|
|
253
|
-
logger.info(`${
|
|
247
|
+
logger.info(`${UNICODE.INFO} certificate not found in ${browserName}`)
|
|
254
248
|
return {
|
|
255
249
|
status: "not_trusted",
|
|
256
250
|
reason: `not found in ${browserName} nss database file`,
|
|
257
251
|
}
|
|
258
252
|
}
|
|
259
|
-
logger.info(`${
|
|
253
|
+
logger.info(`${UNICODE.INFO} found certificate in ${browserName}`)
|
|
260
254
|
logger.info(`Removing certificate from ${browserName}...`)
|
|
261
255
|
await getBrowserClosedPromise()
|
|
262
256
|
await Promise.all(
|
|
@@ -269,7 +263,7 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
269
263
|
await removeFromNSSDB({ NSSDBFileUrl: found })
|
|
270
264
|
}),
|
|
271
265
|
)
|
|
272
|
-
logger.info(`${
|
|
266
|
+
logger.info(`${UNICODE.OK} certificate removed from ${browserName}`)
|
|
273
267
|
return {
|
|
274
268
|
status: "not_trusted",
|
|
275
269
|
reason: `removed from ${browserName} nss database file`,
|
|
@@ -298,7 +292,7 @@ const findNSSDBFiles = async ({ logger, NSSDBDirectoryUrl }) => {
|
|
|
298
292
|
const NSSDBDirectoryExists = existsSync(NSSDBDirectoryPath)
|
|
299
293
|
if (!NSSDBDirectoryExists) {
|
|
300
294
|
logger.info(
|
|
301
|
-
`${
|
|
295
|
+
`${UNICODE.INFO} nss database directory not found on filesystem at ${NSSDBDirectoryPath}`,
|
|
302
296
|
)
|
|
303
297
|
NSSDirectoryCache[NSSDBDirectoryUrl] = []
|
|
304
298
|
return []
|
|
@@ -320,14 +314,14 @@ const findNSSDBFiles = async ({ logger, NSSDBDirectoryUrl }) => {
|
|
|
320
314
|
const fileCount = NSSDBFiles.length
|
|
321
315
|
if (fileCount === 0) {
|
|
322
316
|
logger.warn(
|
|
323
|
-
`${
|
|
317
|
+
`${UNICODE.WARNING} could not find nss database file in ${NSSDBDirectoryUrl}`,
|
|
324
318
|
)
|
|
325
319
|
NSSDirectoryCache[NSSDBDirectoryUrl] = []
|
|
326
320
|
return []
|
|
327
321
|
}
|
|
328
322
|
|
|
329
323
|
logger.debug(
|
|
330
|
-
`${
|
|
324
|
+
`${UNICODE.OK} found ${fileCount} nss database file in ${NSSDBDirectoryUrl}`,
|
|
331
325
|
)
|
|
332
326
|
const files = NSSDBFiles.map((file) => {
|
|
333
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)
|