Skip to content

Commit 34058a6

Browse files
refactor: server (part 2) (#1849)
1 parent a1cdd2a commit 34058a6

File tree

3 files changed

+102
-100
lines changed

3 files changed

+102
-100
lines changed

lib/Server.js

+55-98
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,33 @@
11
'use strict';
22

33
/* eslint-disable
4-
import/order,
54
no-shadow,
65
no-undefined,
76
func-names
87
*/
98
const fs = require('fs');
109
const path = require('path');
11-
12-
const ip = require('ip');
1310
const tls = require('tls');
1411
const url = require('url');
1512
const http = require('http');
1613
const https = require('https');
14+
const ip = require('ip');
1715
const sockjs = require('sockjs');
18-
1916
const semver = require('semver');
20-
2117
const killable = require('killable');
22-
23-
const del = require('del');
2418
const chokidar = require('chokidar');
25-
2619
const express = require('express');
27-
2820
const httpProxyMiddleware = require('http-proxy-middleware');
2921
const historyApiFallback = require('connect-history-api-fallback');
3022
const compress = require('compression');
3123
const serveIndex = require('serve-index');
32-
3324
const webpack = require('webpack');
3425
const webpackDevMiddleware = require('webpack-dev-middleware');
35-
26+
const validateOptions = require('schema-utils');
3627
const updateCompiler = require('./utils/updateCompiler');
3728
const createLogger = require('./utils/createLogger');
38-
const createCertificate = require('./utils/createCertificate');
29+
const getCertificate = require('./utils/getCertificate');
3930
const routes = require('./utils/routes');
40-
41-
const validateOptions = require('schema-utils');
4231
const schema = require('./options.json');
4332

4433
// Workaround for sockjs@~0.3.19
@@ -96,43 +85,41 @@ class Server {
9685

9786
this.log = _log || createLogger(options);
9887

99-
// if the user enables http2, we can safely enable https
100-
if (options.http2 && !options.https) {
101-
options.https = true;
102-
}
103-
10488
this.originalStats =
105-
options.stats && Object.keys(options.stats).length ? options.stats : {};
89+
this.options.stats && Object.keys(this.options.stats).length
90+
? this.options.stats
91+
: {};
10692

107-
this.hot = options.hot || options.hotOnly;
108-
this.headers = options.headers;
109-
this.progress = options.progress;
93+
this.sockets = [];
94+
this.contentBaseWatchers = [];
11095

111-
this.serveIndex = options.serveIndex;
96+
// TODO this.<property> is deprecated (remove them in next major release.) in favor this.options.<property>
97+
this.hot = this.options.hot || this.options.hotOnly;
98+
this.headers = this.options.headers;
99+
this.progress = this.options.progress;
112100

113-
this.clientOverlay = options.overlay;
114-
this.clientLogLevel = options.clientLogLevel;
101+
this.serveIndex = this.options.serveIndex;
115102

116-
this.publicHost = options.public;
117-
this.allowedHosts = options.allowedHosts;
118-
this.disableHostCheck = !!options.disableHostCheck;
103+
this.clientOverlay = this.options.overlay;
104+
this.clientLogLevel = this.options.clientLogLevel;
119105

120-
this.sockets = [];
106+
this.publicHost = this.options.public;
107+
this.allowedHosts = this.options.allowedHosts;
108+
this.disableHostCheck = !!this.options.disableHostCheck;
121109

122-
if (!options.watchOptions) {
123-
options.watchOptions = {};
110+
if (!this.options.watchOptions) {
111+
this.options.watchOptions = {};
124112
}
125-
// ignoring node_modules folder by default
126-
options.watchOptions.ignored = options.watchOptions.ignored || [
113+
// Ignoring node_modules folder by default
114+
this.options.watchOptions.ignored = this.options.watchOptions.ignored || [
127115
/node_modules/,
128116
];
129-
this.watchOptions = options.watchOptions;
117+
this.watchOptions = this.options.watchOptions;
130118

131-
this.contentBaseWatchers = [];
132119
// Replace leading and trailing slashes to normalize path
133120
this.sockPath = `/${
134-
options.sockPath
135-
? options.sockPath.replace(/^\/|\/$/g, '')
121+
this.options.sockPath
122+
? this.options.sockPath.replace(/^\/|\/$/g, '')
136123
: 'sockjs-node'
137124
}`;
138125

@@ -146,28 +133,33 @@ class Server {
146133
this.setupDevMiddleware();
147134

148135
// set express routes
149-
routes(this.app, this.middleware, options);
136+
routes(this.app, this.middleware, this.options);
150137

151138
// Keep track of websocket proxies for external websocket upgrade.
152139
this.websocketProxies = [];
153140

154141
this.setupFeatures();
155142

156-
if (options.https) {
143+
// if the user enables http2, we can safely enable https
144+
if (this.options.http2 && !this.options.https) {
145+
this.options.https = true;
146+
}
147+
148+
if (this.options.https) {
157149
// for keep supporting CLI parameters
158-
if (typeof options.https === 'boolean') {
159-
options.https = {
160-
ca: options.ca,
161-
pfx: options.pfx,
162-
key: options.key,
163-
cert: options.cert,
164-
passphrase: options.pfxPassphrase,
165-
requestCert: options.requestCert || false,
150+
if (typeof this.options.https === 'boolean') {
151+
this.options.https = {
152+
ca: this.options.ca,
153+
pfx: this.options.pfx,
154+
key: this.options.key,
155+
cert: this.options.cert,
156+
passphrase: this.options.pfxPassphrase,
157+
requestCert: this.options.requestCert || false,
166158
};
167159
}
168160

169161
for (const property of ['ca', 'pfx', 'key', 'cert']) {
170-
const value = options.https[property];
162+
const value = this.options.https[property];
171163
const isBuffer = value instanceof Buffer;
172164

173165
if (value && !isBuffer) {
@@ -181,73 +173,38 @@ class Server {
181173

182174
if (stats) {
183175
// It is file
184-
options.https[property] = fs.readFileSync(path.resolve(value));
176+
this.options.https[property] = fs.readFileSync(path.resolve(value));
185177
} else {
186-
options.https[property] = value;
178+
this.options.https[property] = value;
187179
}
188180
}
189181
}
190182

191183
let fakeCert;
192184

193-
if (!options.https.key || !options.https.cert) {
194-
// Use a self-signed certificate if no certificate was configured.
195-
// Cycle certs every 24 hours
196-
const certPath = path.join(__dirname, '../ssl/server.pem');
197-
198-
let certExists = fs.existsSync(certPath);
199-
200-
if (certExists) {
201-
const certTtl = 1000 * 60 * 60 * 24;
202-
const certStat = fs.statSync(certPath);
203-
204-
const now = new Date();
205-
206-
// cert is more than 30 days old, kill it with fire
207-
if ((now - certStat.ctime) / certTtl > 30) {
208-
this.log.info(
209-
'SSL Certificate is more than 30 days old. Removing.'
210-
);
211-
212-
del.sync([certPath], { force: true });
213-
214-
certExists = false;
215-
}
216-
}
217-
218-
if (!certExists) {
219-
this.log.info('Generating SSL Certificate');
220-
221-
const attrs = [{ name: 'commonName', value: 'localhost' }];
222-
const pems = createCertificate(attrs);
223-
224-
fs.writeFileSync(certPath, pems.private + pems.cert, {
225-
encoding: 'utf8',
226-
});
227-
}
228-
229-
fakeCert = fs.readFileSync(certPath);
185+
if (!this.options.https.key || !this.options.https.cert) {
186+
fakeCert = getCertificate(this.log);
230187
}
231188

232-
options.https.key = options.https.key || fakeCert;
233-
options.https.cert = options.https.cert || fakeCert;
189+
this.options.https.key = this.options.https.key || fakeCert;
190+
this.options.https.cert = this.options.https.cert || fakeCert;
234191

235192
// Only prevent HTTP/2 if http2 is explicitly set to false
236-
const isHttp2 = options.http2 !== false;
193+
const isHttp2 = this.options.http2 !== false;
237194

238195
// note that options.spdy never existed. The user was able
239196
// to set options.https.spdy before, though it was not in the
240197
// docs. Keep options.https.spdy if the user sets it for
241198
// backwards compatability, but log a deprecation warning.
242-
if (options.https.spdy) {
199+
if (this.options.https.spdy) {
243200
// for backwards compatability: if options.https.spdy was passed in before,
244201
// it was not altered in any way
245202
this.log.warn(
246203
'Providing custom spdy server options is deprecated and will be removed in the next major version.'
247204
);
248205
} else {
249206
// if the normal https server gets this option, it will not affect it.
250-
options.https.spdy = {
207+
this.options.https.spdy = {
251208
protocols: ['h2', 'http/1.1'],
252209
};
253210
}
@@ -262,21 +219,21 @@ class Server {
262219
// - https://github.com/webpack/webpack-dev-server/issues/1449
263220
// - https://github.com/expressjs/express/issues/3388
264221
if (semver.gte(process.version, '10.0.0') || !isHttp2) {
265-
if (options.http2) {
222+
if (this.options.http2) {
266223
// the user explicitly requested http2 but is not getting it because
267224
// of the node version.
268225
this.log.warn(
269226
'HTTP/2 is currently unsupported for Node 10.0.0 and above, but will be supported once Express supports it'
270227
);
271228
}
272-
this.listeningApp = https.createServer(options.https, this.app);
229+
this.listeningApp = https.createServer(this.options.https, this.app);
273230
} else {
274231
/* eslint-disable global-require */
275232
// The relevant issues are:
276233
// https://github.com/spdy-http2/node-spdy/issues/350
277234
// https://github.com/webpack/webpack-dev-server/issues/1592
278235
this.listeningApp = require('spdy').createServer(
279-
options.https,
236+
this.options.https,
280237
this.app
281238
);
282239
/* eslint-enable global-require */
@@ -941,7 +898,7 @@ class Server {
941898
? this.watchOptions.poll
942899
: undefined;
943900

944-
const options = {
901+
const watchOptions = {
945902
ignoreInitial: true,
946903
persistent: true,
947904
followSymlinks: false,
@@ -953,7 +910,7 @@ class Server {
953910
interval,
954911
};
955912

956-
const watcher = chokidar.watch(watchPath, options);
913+
const watcher = chokidar.watch(watchPath, watchOptions);
957914

958915
watcher.on('change', () => {
959916
this.sockWrite(this.sockets, 'content-changed');

lib/utils/createCertificate.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
const selfsigned = require('selfsigned');
44

5-
function createCertificate(attrs) {
6-
return selfsigned.generate(attrs, {
5+
function createCertificate(attributes) {
6+
return selfsigned.generate(attributes, {
77
algorithm: 'sha256',
88
days: 30,
99
keySize: 2048,

lib/utils/getCertificate.js

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
'use strict';
2+
3+
const path = require('path');
4+
const fs = require('fs');
5+
const del = require('del');
6+
const createCertificate = require('./createCertificate');
7+
8+
function getCertificate(logger) {
9+
// Use a self-signed certificate if no certificate was configured.
10+
// Cycle certs every 24 hours
11+
const certificatePath = path.join(__dirname, '../../ssl/server.pem');
12+
13+
let certificateExists = fs.existsSync(certificatePath);
14+
15+
if (certificateExists) {
16+
const certificateTtl = 1000 * 60 * 60 * 24;
17+
const certificateStat = fs.statSync(certificatePath);
18+
19+
const now = new Date();
20+
21+
// cert is more than 30 days old, kill it with fire
22+
if ((now - certificateStat.ctime) / certificateTtl > 30) {
23+
logger.info('SSL Certificate is more than 30 days old. Removing.');
24+
25+
del.sync([certificatePath], { force: true });
26+
27+
certificateExists = false;
28+
}
29+
}
30+
31+
if (!certificateExists) {
32+
logger.info('Generating SSL Certificate');
33+
34+
const attributes = [{ name: 'commonName', value: 'localhost' }];
35+
const pems = createCertificate(attributes);
36+
37+
fs.writeFileSync(certificatePath, pems.private + pems.cert, {
38+
encoding: 'utf8',
39+
});
40+
}
41+
42+
return fs.readFileSync(certificatePath);
43+
}
44+
45+
module.exports = getCertificate;

0 commit comments

Comments
 (0)