forked from daquinoaldo/https-localhost
-
Notifications
You must be signed in to change notification settings - Fork 0
/
certs.js
193 lines (180 loc) · 6.26 KB
/
certs.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#!/usr/bin/env node
const path = require("path")
const fs = require("fs")
const exec = require("child_process").exec
const https = require("https")
const getAppDataPath = require("appdata-path")
const MKCERT_VERSION = "v1.4.1"
const CERT_PATH = getAppDataPath("https-localhost")
// check for updates
/* istanbul ignore next: cannot test pkg */
function checkUpdates() {
try {
const options = {
host: "api.github.com",
path: "/repos/daquinoaldo/https-localhost/releases/latest",
method: "GET",
headers: { "User-Agent": "node.js" }
}
https.request(options, res => {
let body = ""
res.on("data", chunk => { body += chunk.toString("utf8") })
res.on("end", () => {
const currentVersion = JSON.parse(fs.readFileSync(
path.resolve(__dirname, "package.json"))).version
const latestVersion = JSON.parse(body).tag_name.replace("v", "")
if (currentVersion !== latestVersion)
console.warn("[https-localhost] New update available.")
})
}).end()
} catch (e) {
// Just catch everything, this is not a critic part and can fail.
// It is important to not affect the script behavior.
}
}
// get the executable name
function getExe() {
/* istanbul ignore next: tested on all platform on travis */
switch (process.platform) {
case "darwin":
return "mkcert-" + MKCERT_VERSION + "-darwin-amd64"
case "linux":
if (process.arch === "arm" || process.arch === "arm64")
return "mkcert-" + MKCERT_VERSION + "-linux-arm"
else return "mkcert-" + MKCERT_VERSION + "-linux-amd64"
/* falls through */
case "win32":
return "mkcert-" + MKCERT_VERSION + "-windows-amd64.exe"
default:
console.warn("Cannot generate the localhost certificate on your " +
"platform. Please, consider contacting the developer if you can help.")
process.exit(0)
}
}
// download a binary file
function download(url, path) {
console.log("Downloading the mkcert executable...")
const file = fs.createWriteStream(path)
return new Promise(resolve => {
function get(url, file) {
https.get(url, (response) => {
if (response.statusCode === 302) get(response.headers.location, file)
else response.pipe(file).on("finish", resolve)
})
}
get(url, file)
})
}
// execute the binary executable to generate the certificates
function mkcert(appDataPath, exe, domain) {
// fix problems with spaces
/* istanbul ignore next: platform dependent */
const ensureValidPath = function(path) {
// use apex on Windows
if (process.platform === "win32")
return "\"" + path + "\""
// escape spaces in Mac OS
if (process.platform === "darwin")
return path.replace(/ /g, "\\ ")
return path
}
const logPath = ensureValidPath(path.join(appDataPath, "mkcert.log"))
const errPath = ensureValidPath(path.join(appDataPath, "mkcert.err"))
const exePath = ensureValidPath(path.join(appDataPath, exe))
const crtPath = ensureValidPath(path.join(appDataPath, domain + ".crt"))
const keyPath = ensureValidPath(path.join(appDataPath, domain + ".key"))
const cmd = exePath + " -install -cert-file " + crtPath +
" -key-file " + keyPath + " " + domain
return new Promise((resolve, reject) => {
console.log("Running mkcert to generate certificates...")
exec(cmd, (err, stdout, stderr) => {
// log
const errFun = err => {
/* istanbul ignore if: cannot be tested */
if (err) console.error(err)
}
fs.writeFile(logPath, stdout, errFun)
fs.writeFile(errPath, stderr, errFun)
/* istanbul ignore if: cannot be tested */
if (err) reject(err)
resolve()
})
})
}
async function generate(appDataPath = CERT_PATH, customDomain = undefined) {
const domain = customDomain || "localhost"
console.info("Generating certificates...")
console.log("Certificates path: " + appDataPath +
". Never modify nor share this files.")
// mkdir if not exists
/* istanbul ignore else: not relevant */
if (!fs.existsSync(appDataPath))
fs.mkdirSync(appDataPath, { recursive: true })
// build the executable url and path
const url = "https://github.com/FiloSottile/mkcert/releases/download/" +
MKCERT_VERSION + "/"
const exe = getExe()
const exePath = path.join(appDataPath, exe)
// download the executable
await download(url + exe, exePath)
// make binary executable
fs.chmodSync(exePath, "0755")
// execute the binary
await mkcert(appDataPath, exe, domain)
console.log("Certificates generated, installed and trusted. Ready to go!")
}
async function getCerts(customDomain = undefined) {
const domain = customDomain || "localhost"
const certPath = process.env.CERT_PATH || CERT_PATH
// check for updates if running as executable
/* istanbul ignore if: cannot test pkg */
if (process.pkg) checkUpdates()
// check if a reinstall is forced or needed by a mkcert update
if (process.env.REINSTALL ||
!fs.existsSync(path.join(certPath, getExe())))
await generate(certPath, domain)
try {
return {
key: fs.readFileSync(path.join(certPath, domain + ".key")),
cert: fs.readFileSync(path.join(certPath, domain + ".crt"))
}
} catch (e) {
/* istanbul ignore else: should never occur */
if (certPath !== CERT_PATH) {
console.error("Cannot find localhost.key and localhost.crt in the" +
" specified path: " + certPath)
process.exit(1)
} else {
// Missing certificates (first run)
// generate the certificate
await generate(CERT_PATH, domain)
// recursive call
return getCerts(domain)
}
}
}
// delete a folder and the file inside it
function remove(appDataPath = CERT_PATH) {
if (fs.existsSync(appDataPath)) {
fs.readdirSync(appDataPath)
.forEach(file => fs.unlinkSync(path.join(appDataPath, file)))
fs.rmdirSync(appDataPath)
}
}
// run as script
/* istanbul ignore if: cannot be tested */
if (require.main === module)
// if run with -u or --uninstall
if (process.argv.length === 3 &&
(process.argv[2] === "-u" || process.argv[2] === "--uninstall")) {
remove()
console.info("Certificates removed.")
} else try { // install
generate()
} catch (err) { console.error("\nExec error: " + err) }
// export as module
module.exports = {
getCerts,
generate,
remove
}