Validate SSL config for sanity before startup
| @@ -190,13 +190,46 @@ export class ServerStartup { | |||
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | /** | 192 | /** |
| 193 | * Prints a fatal error message and exits the process. | ||
| 194 | * @param {string} message | ||
| 195 | */ | ||
| 196 | #fatal(message) { | ||
| 197 | console.error(color.red(message)); | ||
| 198 | process.exit(1); | ||
| 199 | } | ||
| 200 | |||
| 201 | /** | ||
| 202 | * Checks if SSL options are valid. If not, it will print an error message and exit the process. | ||
| 203 | * @returns {void} | ||
| 204 | */ | ||
| 205 | #verifySslOptions() { | ||
| 206 | if (!this.cliArgs.ssl) return; | ||
| 207 | |||
| 208 | if (!this.cliArgs.certPath) { | ||
| 209 | this.#fatal('Error: SSL certificate path is required when using HTTPS. Check your config'); | ||
| 210 | } | ||
| 211 | |||
| 212 | if (!this.cliArgs.keyPath) { | ||
| 213 | this.#fatal('Error: SSL key path is required when using HTTPS. Check your config'); | ||
| 214 | } | ||
| 215 | |||
| 216 | if (!fs.existsSync(this.cliArgs.certPath)) { | ||
| 217 | this.#fatal('Error: SSL certificate path does not exist'); | ||
| 218 | } | ||
| 219 | |||
| 220 | if (!fs.existsSync(this.cliArgs.keyPath)) { | ||
| 221 | this.#fatal('Error: SSL key path does not exist'); | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | /** | ||
| 193 | * Creates an HTTPS server. | 226 | * Creates an HTTPS server. |
| 194 | * @param {URL} url The URL to listen on | 227 | * @param {URL} url The URL to listen on |
| 195 | * @param {number} ipVersion the ip version to use | 228 | * @param {number} ipVersion the ip version to use |
| 196 | * @returns {Promise<void>} A promise that resolves when the server is listening | 229 | * @returns {Promise<void>} A promise that resolves when the server is listening |
| 197 | * @throws {Error} If the server fails to start | ||
| 198 | */ | 230 | */ |
| 199 | #createHttpsServer(url, ipVersion) { | 231 | #createHttpsServer(url, ipVersion) { |
| 232 | this.#verifySslOptions(); | ||
| 200 | return new Promise((resolve, reject) => { | 233 | return new Promise((resolve, reject) => { |
| 201 | const sslOptions = { | 234 | const sslOptions = { |
| 202 | cert: fs.readFileSync(this.cliArgs.certPath), | 235 | cert: fs.readFileSync(this.cliArgs.certPath), |
| @@ -222,7 +255,6 @@ export class ServerStartup { | |||
| 222 | * @param {URL} url The URL to listen on | 255 | * @param {URL} url The URL to listen on |
| 223 | * @param {number} ipVersion the ip version to use | 256 | * @param {number} ipVersion the ip version to use |
| 224 | * @returns {Promise<void>} A promise that resolves when the server is listening | 257 | * @returns {Promise<void>} A promise that resolves when the server is listening |
| 225 | * @throws {Error} If the server fails to start | ||
| 226 | */ | 258 | */ |
| 227 | #createHttpServer(url, ipVersion) { | 259 | #createHttpServer(url, ipVersion) { |
| 228 | return new Promise((resolve, reject) => { | 260 | return new Promise((resolve, reject) => { |
| @@ -257,7 +289,7 @@ export class ServerStartup { | |||
| 257 | try { | 289 | try { |
| 258 | await createFunc(this.cliArgs.getIPv6ListenUrl(), 6); | 290 | await createFunc(this.cliArgs.getIPv6ListenUrl(), 6); |
| 259 | } catch (error) { | 291 | } catch (error) { |
| 260 | console.error('non-fatal error: failed to start server on IPv6'); | 292 | console.error('Warning: failed to start server on IPv6'); |
| 261 | console.error(error); | 293 | console.error(error); |
| 262 | 294 | ||
| 263 | v6Failed = true; | 295 | v6Failed = true; |
| @@ -268,7 +300,7 @@ export class ServerStartup { | |||
| 268 | try { | 300 | try { |
| 269 | await createFunc(this.cliArgs.getIPv4ListenUrl(), 4); | 301 | await createFunc(this.cliArgs.getIPv4ListenUrl(), 4); |
| 270 | } catch (error) { | 302 | } catch (error) { |
| 271 | console.error('non-fatal error: failed to start server on IPv4'); | 303 | console.error('Warning: failed to start server on IPv4'); |
| 272 | console.error(error); | 304 | console.error(error); |
| 273 | 305 | ||
| 274 | v4Failed = true; | 306 | v4Failed = true; |
| @@ -285,18 +317,15 @@ export class ServerStartup { | |||
| 285 | */ | 317 | */ |
| 286 | #handleServerListenFail({ v6Failed, v4Failed, useIPv6, useIPv4 }) { | 318 | #handleServerListenFail({ v6Failed, v4Failed, useIPv6, useIPv4 }) { |
| 287 | if (v6Failed && !useIPv4) { | 319 | if (v6Failed && !useIPv4) { |
| 288 | console.error(color.red('fatal error: Failed to start server on IPv6 and IPv4 disabled')); | 320 | this.#fatal('Error: Failed to start server on IPv6 and IPv4 disabled'); |
| 289 | process.exit(1); | ||
| 290 | } | 321 | } |
| 291 | 322 | ||
| 292 | if (v4Failed && !useIPv6) { | 323 | if (v4Failed && !useIPv6) { |
| 293 | console.error(color.red('fatal error: Failed to start server on IPv4 and IPv6 disabled')); | 324 | this.#fatal('Error: Failed to start server on IPv4 and IPv6 disabled'); |
| 294 | process.exit(1); | ||
| 295 | } | 325 | } |
| 296 | 326 | ||
| 297 | if (v6Failed && v4Failed) { | 327 | if (v6Failed && v4Failed) { |
| 298 | console.error(color.red('fatal error: Failed to start server on both IPv6 and IPv4')); | 328 | this.#fatal('Error: Failed to start server on both IPv6 and IPv4'); |
| 299 | process.exit(1); | ||
| 300 | } | 329 | } |
| 301 | } | 330 | } |
| 302 | 331 | ||