From 9c88c30ac3c3c99e5717e9281962539a40e36c66 Mon Sep 17 00:00:00 2001 From: Alex Brazier Date: Sat, 17 Nov 2018 19:15:52 +0000 Subject: [PATCH 01/12] Add option to provide custom SSL certificates when using HTTPS --- .../config/webpackDevServer.config.js | 54 +++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/packages/react-scripts/config/webpackDevServer.config.js b/packages/react-scripts/config/webpackDevServer.config.js index 60a9713df33..1e38bc7ed60 100644 --- a/packages/react-scripts/config/webpackDevServer.config.js +++ b/packages/react-scripts/config/webpackDevServer.config.js @@ -8,16 +8,64 @@ // @remove-on-eject-end 'use strict'; +const fs = require('fs'); +const path = require('path'); +const chalk = require('chalk'); +const crypto = require('crypto'); const errorOverlayMiddleware = require('react-dev-utils/errorOverlayMiddleware'); const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware'); const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware'); const ignoredFiles = require('react-dev-utils/ignoredFiles'); const paths = require('./paths'); -const fs = require('fs'); -const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; const host = process.env.HOST || '0.0.0.0'; +// Get the https config +// Return cert files if provided in env, otherwise just true or false +function httpsConfig() { + const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env; + const https = HTTPS === 'true'; + + if (https && SSL_CRT_FILE && SSL_KEY_FILE) { + const cwd = process.cwd(); + const crtFile = path.resolve(cwd, SSL_CRT_FILE); + const keyFile = path.resolve(cwd, SSL_KEY_FILE); + if (!fs.existsSync(crtFile)) { + throw new Error( + `You specified ${chalk.cyan( + 'SSL_CRT_FILE' + )} in your env, but the file "${chalk.yellow(crtFile)}" doesn't exist.` + ); + } + if (!fs.existsSync(keyFile)) { + throw new Error( + `You specified ${chalk.cyan( + 'SSL_KEY_FILE' + )} in your env, but the file "${chalk.yellow(keyFile)}" doesn't exist.` + ); + } + const config = { + key: fs.readFileSync(keyFile), + cert: fs.readFileSync(crtFile), + }; + try { + crypto.publicEncrypt(config.cert, new Buffer('')); + } catch (err) { + throw new Error(`The certificate "${chalk.yellow(crtFile)}" is invalid.`); + } + + try { + crypto.privateEncrypt(config.key, new Buffer('')); + } catch (err) { + throw new Error( + `The certificate key "${chalk.yellow(keyFile)}" is invalid.` + ); + } + return config; + } + return https; +} + module.exports = function(proxy, allowedHost) { return { // WebpackDevServer 2.4.3 introduced a security fix that prevents remote @@ -80,7 +128,7 @@ module.exports = function(proxy, allowedHost) { ignored: ignoredFiles(paths.appSrc), }, // Enable HTTPS if the HTTPS environment variable is set to 'true' - https: protocol === 'https', + https: httpsConfig(), host, overlay: false, historyApiFallback: { From 3d7388cffd8779d12440e96799b791326c0e7ce2 Mon Sep 17 00:00:00 2001 From: Alex Brazier Date: Sat, 17 Nov 2018 20:05:21 +0000 Subject: [PATCH 02/12] Update documentation with custom HTTPS certs --- docusaurus/docs/using-https-in-development.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docusaurus/docs/using-https-in-development.md b/docusaurus/docs/using-https-in-development.md index 4dbb2536d70..857aebce483 100644 --- a/docusaurus/docs/using-https-in-development.md +++ b/docusaurus/docs/using-https-in-development.md @@ -31,3 +31,9 @@ HTTPS=true npm start ``` Note that the server will use a self-signed certificate, so your web browser will almost definitely display a warning upon accessing the page. + +If this is an issue you can also specify a custom certificate from `react-scripts@2.2.0` and higher. + +To do this set `SSL_CRT_FILE` and `SSL_KEY_FILE` to the path of the certificate and key files in the same way you do for `HTTPS` above. You will also need to set `HTTPS=true`. + +e.g. `SSL_CRT_FILE=cert.crt` and `SSL_KEY_FILE=cert.key` From ab6b1124c0c036dfcd5b4f2004e05c91a0ded820 Mon Sep 17 00:00:00 2001 From: Alex Brazier Date: Mon, 10 Dec 2018 22:32:46 +0000 Subject: [PATCH 03/12] Improve certificate validation and move to its own file --- packages/react-scripts/config/https.js | 72 +++++++++++++++++++ .../config/webpackDevServer.config.js | 52 +------------- 2 files changed, 74 insertions(+), 50 deletions(-) create mode 100644 packages/react-scripts/config/https.js diff --git a/packages/react-scripts/config/https.js b/packages/react-scripts/config/https.js new file mode 100644 index 00000000000..9b82ac53e83 --- /dev/null +++ b/packages/react-scripts/config/https.js @@ -0,0 +1,72 @@ +// @remove-on-eject-begin +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +// @remove-on-eject-end +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const chalk = require('chalk'); +const crypto = require('crypto'); +const paths = require('./paths'); + +// Ensure the certificate and key provided are valid and if not +// throw an easy to debug error +function validateKeyAndCerts({ cert, key, keyFile, crtFile }) { + let encrypted; + try { + // publicEncrypt will throw an error with an invalid cert + encrypted = crypto.publicEncrypt(cert, Buffer.from('test')); + } catch (err) { + throw new Error(`The certificate "${chalk.yellow(crtFile)}" is invalid.`); + } + + try { + // privateDecrypt will throw an error with an invalid key + crypto.privateDecrypt(key, encrypted); + } catch (err) { + throw new Error( + `The certificate key "${chalk.yellow(keyFile)}" is invalid.` + ); + } +} + +// Get the https config +// Return cert files if provided in env, otherwise just true or false +function httpsConfig() { + const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env; + const https = HTTPS === 'true'; + + if (https && SSL_CRT_FILE && SSL_KEY_FILE) { + const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE); + const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE); + if (!fs.existsSync(crtFile)) { + throw new Error( + `You specified ${chalk.cyan( + 'SSL_CRT_FILE' + )} in your env, but the file "${chalk.yellow(crtFile)}" doesn't exist.` + ); + } + if (!fs.existsSync(keyFile)) { + throw new Error( + `You specified ${chalk.cyan( + 'SSL_KEY_FILE' + )} in your env, but the file "${chalk.yellow(keyFile)}" doesn't exist.` + ); + } + const config = { + key: fs.readFileSync(keyFile), + cert: fs.readFileSync(crtFile), + }; + + validateKeyAndCerts({ ...config, keyFile, crtFile }); + return config; + } + return https; +} + +module.exports = httpsConfig; diff --git a/packages/react-scripts/config/webpackDevServer.config.js b/packages/react-scripts/config/webpackDevServer.config.js index 1e38bc7ed60..4da8728abf3 100644 --- a/packages/react-scripts/config/webpackDevServer.config.js +++ b/packages/react-scripts/config/webpackDevServer.config.js @@ -9,63 +9,15 @@ 'use strict'; const fs = require('fs'); -const path = require('path'); -const chalk = require('chalk'); -const crypto = require('crypto'); const errorOverlayMiddleware = require('react-dev-utils/errorOverlayMiddleware'); const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware'); const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware'); const ignoredFiles = require('react-dev-utils/ignoredFiles'); const paths = require('./paths'); +const https = require('./https'); const host = process.env.HOST || '0.0.0.0'; -// Get the https config -// Return cert files if provided in env, otherwise just true or false -function httpsConfig() { - const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env; - const https = HTTPS === 'true'; - - if (https && SSL_CRT_FILE && SSL_KEY_FILE) { - const cwd = process.cwd(); - const crtFile = path.resolve(cwd, SSL_CRT_FILE); - const keyFile = path.resolve(cwd, SSL_KEY_FILE); - if (!fs.existsSync(crtFile)) { - throw new Error( - `You specified ${chalk.cyan( - 'SSL_CRT_FILE' - )} in your env, but the file "${chalk.yellow(crtFile)}" doesn't exist.` - ); - } - if (!fs.existsSync(keyFile)) { - throw new Error( - `You specified ${chalk.cyan( - 'SSL_KEY_FILE' - )} in your env, but the file "${chalk.yellow(keyFile)}" doesn't exist.` - ); - } - const config = { - key: fs.readFileSync(keyFile), - cert: fs.readFileSync(crtFile), - }; - try { - crypto.publicEncrypt(config.cert, new Buffer('')); - } catch (err) { - throw new Error(`The certificate "${chalk.yellow(crtFile)}" is invalid.`); - } - - try { - crypto.privateEncrypt(config.key, new Buffer('')); - } catch (err) { - throw new Error( - `The certificate key "${chalk.yellow(keyFile)}" is invalid.` - ); - } - return config; - } - return https; -} - module.exports = function(proxy, allowedHost) { return { // WebpackDevServer 2.4.3 introduced a security fix that prevents remote @@ -128,7 +80,7 @@ module.exports = function(proxy, allowedHost) { ignored: ignoredFiles(paths.appSrc), }, // Enable HTTPS if the HTTPS environment variable is set to 'true' - https: httpsConfig(), + https: https(), host, overlay: false, historyApiFallback: { From 5de0e3e2e0adf428cb205ae6f63e2567b3a1a94e Mon Sep 17 00:00:00 2001 From: Alex Brazier Date: Mon, 27 May 2019 11:55:00 +0100 Subject: [PATCH 04/12] Update https in development docs Co-Authored-By: Brody McKee --- docusaurus/docs/using-https-in-development.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docusaurus/docs/using-https-in-development.md b/docusaurus/docs/using-https-in-development.md index 857aebce483..b617edb3275 100644 --- a/docusaurus/docs/using-https-in-development.md +++ b/docusaurus/docs/using-https-in-development.md @@ -32,8 +32,8 @@ HTTPS=true npm start Note that the server will use a self-signed certificate, so your web browser will almost definitely display a warning upon accessing the page. -If this is an issue you can also specify a custom certificate from `react-scripts@2.2.0` and higher. +You can also specify a custom certificate (available in `react-scripts@2.2.0` and higher). -To do this set `SSL_CRT_FILE` and `SSL_KEY_FILE` to the path of the certificate and key files in the same way you do for `HTTPS` above. You will also need to set `HTTPS=true`. +To set a custom certificate, set the `SSL_CRT_FILE` and `SSL_KEY_FILE` environment variables to the path of the certificate and key files in the same way you do for `HTTPS` above. Note that you will also need to set `HTTPS=true`. e.g. `SSL_CRT_FILE=cert.crt` and `SSL_KEY_FILE=cert.key` From 3480786fbf581a4a01e4ca04090779832ca36851 Mon Sep 17 00:00:00 2001 From: Alex Brazier Date: Mon, 27 May 2019 12:01:20 +0100 Subject: [PATCH 05/12] Add custom cert example to docs --- docusaurus/docs/using-https-in-development.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docusaurus/docs/using-https-in-development.md b/docusaurus/docs/using-https-in-development.md index b617edb3275..2c0223aa3a8 100644 --- a/docusaurus/docs/using-https-in-development.md +++ b/docusaurus/docs/using-https-in-development.md @@ -36,4 +36,8 @@ You can also specify a custom certificate (available in `react-scripts@2.2.0` an To set a custom certificate, set the `SSL_CRT_FILE` and `SSL_KEY_FILE` environment variables to the path of the certificate and key files in the same way you do for `HTTPS` above. Note that you will also need to set `HTTPS=true`. -e.g. `SSL_CRT_FILE=cert.crt` and `SSL_KEY_FILE=cert.key` +### Custom SSL certificate using Linux, macOS (Bash) + +```bash +HTTPS=true SSL_CRT_FILE=cert.crt SSL_KEY_FILE=cert.key npm start +``` From ae89550f75a2cfa62e31ad2e40cbf6af386691cb Mon Sep 17 00:00:00 2001 From: Alex Brazier Date: Mon, 27 May 2019 12:20:13 +0100 Subject: [PATCH 06/12] Rename https file and update error message --- .../config/{https.js => getHttpsConfig.js} | 40 +++++++++---------- .../config/webpackDevServer.config.js | 5 +-- 2 files changed, 21 insertions(+), 24 deletions(-) rename packages/react-scripts/config/{https.js => getHttpsConfig.js} (68%) diff --git a/packages/react-scripts/config/https.js b/packages/react-scripts/config/getHttpsConfig.js similarity index 68% rename from packages/react-scripts/config/https.js rename to packages/react-scripts/config/getHttpsConfig.js index 9b82ac53e83..0fa72f9f64c 100644 --- a/packages/react-scripts/config/https.js +++ b/packages/react-scripts/config/getHttpsConfig.js @@ -35,38 +35,36 @@ function validateKeyAndCerts({ cert, key, keyFile, crtFile }) { } } +// Read file and throw an error if it doesn't exist +function readEnvFile(file, type) { + if (!fs.existsSync(file)) { + throw new Error( + `You specified ${chalk.cyan( + type + )} in your env, but the file "${chalk.yellow(file)}" can't be found.` + ); + } + return fs.readFileSync(file); +} + // Get the https config // Return cert files if provided in env, otherwise just true or false -function httpsConfig() { +function getHttpsConfig() { const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env; - const https = HTTPS === 'true'; + const isHttps = HTTPS === 'true'; - if (https && SSL_CRT_FILE && SSL_KEY_FILE) { + if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) { const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE); const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE); - if (!fs.existsSync(crtFile)) { - throw new Error( - `You specified ${chalk.cyan( - 'SSL_CRT_FILE' - )} in your env, but the file "${chalk.yellow(crtFile)}" doesn't exist.` - ); - } - if (!fs.existsSync(keyFile)) { - throw new Error( - `You specified ${chalk.cyan( - 'SSL_KEY_FILE' - )} in your env, but the file "${chalk.yellow(keyFile)}" doesn't exist.` - ); - } const config = { - key: fs.readFileSync(keyFile), - cert: fs.readFileSync(crtFile), + cert: readEnvFile(crtFile, 'SSL_CRT_FILE'), + key: readEnvFile(keyFile, 'SSL_KEY_FILE'), }; validateKeyAndCerts({ ...config, keyFile, crtFile }); return config; } - return https; + return isHttps; } -module.exports = httpsConfig; +module.exports = getHttpsConfig; diff --git a/packages/react-scripts/config/webpackDevServer.config.js b/packages/react-scripts/config/webpackDevServer.config.js index 4da8728abf3..eb4936ab89e 100644 --- a/packages/react-scripts/config/webpackDevServer.config.js +++ b/packages/react-scripts/config/webpackDevServer.config.js @@ -14,7 +14,7 @@ const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware'); const ignoredFiles = require('react-dev-utils/ignoredFiles'); const paths = require('./paths'); -const https = require('./https'); +const getHttpsConfig = require('./getHttpsConfig'); const host = process.env.HOST || '0.0.0.0'; @@ -79,8 +79,7 @@ module.exports = function(proxy, allowedHost) { watchOptions: { ignored: ignoredFiles(paths.appSrc), }, - // Enable HTTPS if the HTTPS environment variable is set to 'true' - https: https(), + https: getHttpsConfig(), host, overlay: false, historyApiFallback: { From 3ec78d55ecdca53c758c8f104f3678ff957a6a02 Mon Sep 17 00:00:00 2001 From: Alex Brazier Date: Mon, 27 May 2019 13:00:20 +0100 Subject: [PATCH 07/12] Include original error message when custom ssl cert is invalid --- packages/react-scripts/config/getHttpsConfig.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/react-scripts/config/getHttpsConfig.js b/packages/react-scripts/config/getHttpsConfig.js index 0fa72f9f64c..41c73b5fbe8 100644 --- a/packages/react-scripts/config/getHttpsConfig.js +++ b/packages/react-scripts/config/getHttpsConfig.js @@ -22,7 +22,9 @@ function validateKeyAndCerts({ cert, key, keyFile, crtFile }) { // publicEncrypt will throw an error with an invalid cert encrypted = crypto.publicEncrypt(cert, Buffer.from('test')); } catch (err) { - throw new Error(`The certificate "${chalk.yellow(crtFile)}" is invalid.`); + throw new Error( + `The certificate "${chalk.yellow(crtFile)}" is invalid.\n${err.message}` + ); } try { @@ -30,7 +32,9 @@ function validateKeyAndCerts({ cert, key, keyFile, crtFile }) { crypto.privateDecrypt(key, encrypted); } catch (err) { throw new Error( - `The certificate key "${chalk.yellow(keyFile)}" is invalid.` + `The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${ + err.message + }` ); } } From 81dbb8ef552f6a024d42f9e75792142f6f3f93bd Mon Sep 17 00:00:00 2001 From: Alex Brazier Date: Mon, 27 May 2019 13:06:50 +0100 Subject: [PATCH 08/12] Add chalk to react-scripts dependencies --- packages/react-scripts/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json index e4a93a37e03..edff84fb06c 100644 --- a/packages/react-scripts/package.json +++ b/packages/react-scripts/package.json @@ -39,6 +39,7 @@ "babel-preset-react-app": "^9.0.0", "camelcase": "^5.2.0", "case-sensitive-paths-webpack-plugin": "2.2.0", + "chalk": "2.4.2", "css-loader": "2.1.1", "dotenv": "6.2.0", "dotenv-expand": "4.2.0", From 3671f39f47396202eb1a265fffa56ffcfc6243a8 Mon Sep 17 00:00:00 2001 From: Alex Brazier Date: Thu, 19 Sep 2019 20:46:28 +0100 Subject: [PATCH 09/12] Bump docs version to say that the new config will be available in 3.2.0 --- docusaurus/docs/using-https-in-development.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docusaurus/docs/using-https-in-development.md b/docusaurus/docs/using-https-in-development.md index 2c0223aa3a8..aef6fcfbf33 100644 --- a/docusaurus/docs/using-https-in-development.md +++ b/docusaurus/docs/using-https-in-development.md @@ -32,7 +32,7 @@ HTTPS=true npm start Note that the server will use a self-signed certificate, so your web browser will almost definitely display a warning upon accessing the page. -You can also specify a custom certificate (available in `react-scripts@2.2.0` and higher). +You can also specify a custom certificate (available in `react-scripts@3.2.0` and higher). To set a custom certificate, set the `SSL_CRT_FILE` and `SSL_KEY_FILE` environment variables to the path of the certificate and key files in the same way you do for `HTTPS` above. Note that you will also need to set `HTTPS=true`. From 6d4d9ea5a0d79a2e75ed044dc56e8e2d144e4de2 Mon Sep 17 00:00:00 2001 From: Alex Brazier Date: Fri, 24 Jan 2020 12:15:10 +0000 Subject: [PATCH 10/12] Remove chalk dependency --- packages/react-scripts/config/getHttpsConfig.js | 2 +- packages/react-scripts/package.json | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/react-scripts/config/getHttpsConfig.js b/packages/react-scripts/config/getHttpsConfig.js index 41c73b5fbe8..4fec7936b2f 100644 --- a/packages/react-scripts/config/getHttpsConfig.js +++ b/packages/react-scripts/config/getHttpsConfig.js @@ -10,8 +10,8 @@ const fs = require('fs'); const path = require('path'); -const chalk = require('chalk'); const crypto = require('crypto'); +const chalk = require('react-dev-utils/chalk'); const paths = require('./paths'); // Ensure the certificate and key provided are valid and if not diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json index cae5e63d8d6..d4958051c55 100644 --- a/packages/react-scripts/package.json +++ b/packages/react-scripts/package.json @@ -39,7 +39,6 @@ "babel-preset-react-app": "^9.0.2", "camelcase": "^5.2.0", "case-sensitive-paths-webpack-plugin": "2.2.0", - "chalk": "2.4.2", "css-loader": "3.2.0", "dotenv": "8.2.0", "dotenv-expand": "5.1.0", From a5ab56d892c9c836b97098a0a55ecc3fd8cc7d56 Mon Sep 17 00:00:00 2001 From: Alex Brazier Date: Fri, 24 Jan 2020 12:35:21 +0000 Subject: [PATCH 11/12] Update custom ssl version to 3.4.0 in docs --- docusaurus/docs/using-https-in-development.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docusaurus/docs/using-https-in-development.md b/docusaurus/docs/using-https-in-development.md index a5eb1c98204..a7873e02287 100644 --- a/docusaurus/docs/using-https-in-development.md +++ b/docusaurus/docs/using-https-in-development.md @@ -35,7 +35,7 @@ Note that the server will use a self-signed certificate, so your web browser wil ## Custom SSL certificate -You can also specify a custom certificate (available in `react-scripts@3.3.0` and higher). +You can also specify a custom certificate (available in `react-scripts@3.4.0` and higher). To set a custom certificate, set the `SSL_CRT_FILE` and `SSL_KEY_FILE` environment variables to the path of the certificate and key files in the same way you do for `HTTPS` above. Note that you will also need to set `HTTPS=true`. From b029ef3660e0399e8783bb9749badc30d3d12ee8 Mon Sep 17 00:00:00 2001 From: Alex Brazier Date: Fri, 31 Jan 2020 12:19:37 +0000 Subject: [PATCH 12/12] Remove version from custom ssl certificate docs --- docusaurus/docs/using-https-in-development.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docusaurus/docs/using-https-in-development.md b/docusaurus/docs/using-https-in-development.md index a7873e02287..edd668836d4 100644 --- a/docusaurus/docs/using-https-in-development.md +++ b/docusaurus/docs/using-https-in-development.md @@ -35,8 +35,6 @@ Note that the server will use a self-signed certificate, so your web browser wil ## Custom SSL certificate -You can also specify a custom certificate (available in `react-scripts@3.4.0` and higher). - To set a custom certificate, set the `SSL_CRT_FILE` and `SSL_KEY_FILE` environment variables to the path of the certificate and key files in the same way you do for `HTTPS` above. Note that you will also need to set `HTTPS=true`. ### Linux, macOS (Bash)