Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to provide custom ssl certificates during development #5845

Merged
merged 15 commits into from
Jan 31, 2020
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docusaurus/docs/using-https-in-development.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,13 @@ 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).
alexbrazier marked this conversation as resolved.
Show resolved Hide resolved

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`.

### Custom SSL certificate using Linux, macOS (Bash)

```bash
HTTPS=true SSL_CRT_FILE=cert.crt SSL_KEY_FILE=cert.key npm start
```
74 changes: 74 additions & 0 deletions packages/react-scripts/config/getHttpsConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// @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.\n${err.message}`
);
}

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.\n${
err.message
}`
);
}
}

// 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 getHttpsConfig() {
const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env;
const isHttps = HTTPS === 'true';

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);
const config = {
cert: readEnvFile(crtFile, 'SSL_CRT_FILE'),
key: readEnvFile(keyFile, 'SSL_KEY_FILE'),
};

validateKeyAndCerts({ ...config, keyFile, crtFile });
return config;
}
return isHttps;
}

module.exports = getHttpsConfig;
7 changes: 3 additions & 4 deletions packages/react-scripts/config/webpackDevServer.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@
// @remove-on-eject-end
'use strict';

const fs = require('fs');
mrmckeb marked this conversation as resolved.
Show resolved Hide resolved
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 getHttpsConfig = require('./getHttpsConfig');

const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
const host = process.env.HOST || '0.0.0.0';

module.exports = function(proxy, allowedHost) {
Expand Down Expand Up @@ -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: protocol === 'https',
https: getHttpsConfig(),
host,
overlay: false,
historyApiFallback: {
Expand Down
1 change: 1 addition & 0 deletions packages/react-scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down