Skip to content

Commit 0299c0e

Browse files
alexbraziermrmckeb
andauthored
Add option to provide custom ssl certificates during development (#5845)
* Add option to provide custom SSL certificates when using HTTPS * Update documentation with custom HTTPS certs * Improve certificate validation and move to its own file * Update https in development docs Co-Authored-By: Brody McKee <mrmckeb@users.noreply.github.com> * Add custom cert example to docs * Rename https file and update error message * Include original error message when custom ssl cert is invalid * Add chalk to react-scripts dependencies * Bump docs version to say that the new config will be available in 3.2.0 * Remove chalk dependency * Update custom ssl version to 3.4.0 in docs * Remove version from custom ssl certificate docs Co-authored-by: Brody McKee <mrmckeb@users.noreply.github.com>
1 parent 822422c commit 0299c0e

File tree

3 files changed

+90
-4
lines changed

3 files changed

+90
-4
lines changed

docusaurus/docs/using-https-in-development.md

+13
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,18 @@ HTTPS=true npm start
3232

3333
Note that the server will use a self-signed certificate, so your web browser will almost definitely display a warning upon accessing the page.
3434

35+
36+
## Custom SSL certificate
37+
38+
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`.
39+
40+
### Linux, macOS (Bash)
41+
42+
```bash
43+
HTTPS=true SSL_CRT_FILE=cert.crt SSL_KEY_FILE=cert.key npm start
44+
```
45+
46+
3547
To avoid having to set the environment variable each time, you can either include in the `npm start` script like so:
3648

3749
```json
@@ -42,3 +54,4 @@ To avoid having to set the environment variable each time, you can either includ
4254

4355
Or you can create a `.env` file with `HTTPS=true` set.
4456
[Learn more about environment variables in CRA](https://create-react-app.dev/docs/adding-custom-environment-variables).
57+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// @remove-on-eject-begin
2+
/**
3+
* Copyright (c) 2015-present, Facebook, Inc.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
// @remove-on-eject-end
9+
'use strict';
10+
11+
const fs = require('fs');
12+
const path = require('path');
13+
const crypto = require('crypto');
14+
const chalk = require('react-dev-utils/chalk');
15+
const paths = require('./paths');
16+
17+
// Ensure the certificate and key provided are valid and if not
18+
// throw an easy to debug error
19+
function validateKeyAndCerts({ cert, key, keyFile, crtFile }) {
20+
let encrypted;
21+
try {
22+
// publicEncrypt will throw an error with an invalid cert
23+
encrypted = crypto.publicEncrypt(cert, Buffer.from('test'));
24+
} catch (err) {
25+
throw new Error(
26+
`The certificate "${chalk.yellow(crtFile)}" is invalid.\n${err.message}`
27+
);
28+
}
29+
30+
try {
31+
// privateDecrypt will throw an error with an invalid key
32+
crypto.privateDecrypt(key, encrypted);
33+
} catch (err) {
34+
throw new Error(
35+
`The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${
36+
err.message
37+
}`
38+
);
39+
}
40+
}
41+
42+
// Read file and throw an error if it doesn't exist
43+
function readEnvFile(file, type) {
44+
if (!fs.existsSync(file)) {
45+
throw new Error(
46+
`You specified ${chalk.cyan(
47+
type
48+
)} in your env, but the file "${chalk.yellow(file)}" can't be found.`
49+
);
50+
}
51+
return fs.readFileSync(file);
52+
}
53+
54+
// Get the https config
55+
// Return cert files if provided in env, otherwise just true or false
56+
function getHttpsConfig() {
57+
const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env;
58+
const isHttps = HTTPS === 'true';
59+
60+
if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) {
61+
const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE);
62+
const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE);
63+
const config = {
64+
cert: readEnvFile(crtFile, 'SSL_CRT_FILE'),
65+
key: readEnvFile(keyFile, 'SSL_KEY_FILE'),
66+
};
67+
68+
validateKeyAndCerts({ ...config, keyFile, crtFile });
69+
return config;
70+
}
71+
return isHttps;
72+
}
73+
74+
module.exports = getHttpsConfig;

packages/react-scripts/config/webpackDevServer.config.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88
// @remove-on-eject-end
99
'use strict';
1010

11+
const fs = require('fs');
1112
const errorOverlayMiddleware = require('react-dev-utils/errorOverlayMiddleware');
1213
const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware');
1314
const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware');
1415
const ignoredFiles = require('react-dev-utils/ignoredFiles');
1516
const paths = require('./paths');
16-
const fs = require('fs');
17+
const getHttpsConfig = require('./getHttpsConfig');
1718

18-
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
1919
const host = process.env.HOST || '0.0.0.0';
2020
const sockHost = process.env.WDS_SOCKET_HOST;
2121
const sockPath = process.env.WDS_SOCKET_PATH; // default: '/sockjs-node'
@@ -94,8 +94,7 @@ module.exports = function(proxy, allowedHost) {
9494
watchOptions: {
9595
ignored: ignoredFiles(paths.appSrc),
9696
},
97-
// Enable HTTPS if the HTTPS environment variable is set to 'true'
98-
https: protocol === 'https',
97+
https: getHttpsConfig(),
9998
host,
10099
overlay: false,
101100
historyApiFallback: {

0 commit comments

Comments
 (0)