Skip to content

Commit 03002ef

Browse files
committed
feat(@angular/cli): add host check flags to ng serve
Two new flags are added to `ng serve`: - `--public-host` (aliased by `--live-reload-client): Specify the URL that the browser client will use. - `--disable-host-check`: Don't verify connected clients are part of allowed hosts. Setting `--disable-host-check` will output a warning: ``` WARNING Running a server with --disable-host-check is a security risk. See https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a for more information. ``` See #6070 for more context about this change. Fix #6070
1 parent 818936e commit 03002ef

File tree

8 files changed

+88
-14
lines changed

8 files changed

+88
-14
lines changed

docs/documentation/serve.md

+13-3
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,22 @@ All the build Options are available in serve, below are the additional options.
3939
</details>
4040

4141
<details>
42-
<summary>live-reload-client</summary>
42+
<summary>public-host</summary>
4343
<p>
44-
<code>--live-reload-client</code>
44+
<code>--public</code> (aliases: <code>--live-reload-client</code>)
4545
</p>
4646
<p>
47-
Specify the URL that the live reload browser client will use.
47+
Specify the URL that the browser client will use.
48+
</p>
49+
</details>
50+
51+
<details>
52+
<summary>disable-host-check</summary>
53+
<p>
54+
<code>--disable-host-check</code> <em>default value: false</em>
55+
</p>
56+
<p>
57+
Don't verify connected clients are part of allowed hosts.
4858
</p>
4959
</details>
5060

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@
9696
"url-loader": "^0.5.7",
9797
"walk-sync": "^0.3.1",
9898
"webpack": "~2.4.0",
99-
"webpack-dev-server": "~2.4.2",
99+
"webpack-dev-server": "~2.4.5",
100100
"webpack-merge": "^2.4.0",
101101
"zone.js": "^0.8.4"
102102
},

packages/@angular/cli/commands/serve.ts

+11-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ export interface ServeTaskOptions extends BuildOptions {
2020
host?: string;
2121
proxyConfig?: string;
2222
liveReload?: boolean;
23-
liveReloadClient?: string;
23+
publicHost?: string;
24+
disableHostCheck?: boolean;
2425
ssl?: boolean;
2526
sslKey?: string;
2627
sslCert?: string;
@@ -84,9 +85,16 @@ export const baseServeCommandOptions: any = overrideOptions([
8485
description: 'Whether to reload the page on change, using live-reload.'
8586
},
8687
{
87-
name: 'live-reload-client',
88+
name: 'public-host',
8889
type: String,
89-
description: 'Specify the URL that the live reload browser client will use.'
90+
aliases: ['live-reload-client'],
91+
description: 'Specify the URL that the browser client will use.'
92+
},
93+
{
94+
name: 'disable-host-check',
95+
type: Boolean,
96+
default: false,
97+
description: 'Don\'t verify connected clients are part of allowed hosts.',
9098
},
9199
{
92100
name: 'hmr',

packages/@angular/cli/custom-typings.d.ts

+2
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,6 @@ interface IWebpackDevServerConfigurationOptions {
2121
key?: string;
2222
cert?: string;
2323
overlay?: boolean | { errors: boolean, warnings: boolean };
24+
public?: string;
25+
disableHostCheck?: boolean;
2426
}

packages/@angular/cli/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
"url-loader": "^0.5.7",
8282
"walk-sync": "^0.3.1",
8383
"webpack": "~2.4.0",
84-
"webpack-dev-server": "~2.4.2",
84+
"webpack-dev-server": "~2.4.5",
8585
"webpack-merge": "^2.4.0",
8686
"zone.js": "^0.8.4"
8787
},

packages/@angular/cli/tasks/serve.ts

+16-5
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,18 @@ export default Task.extend({
4747
hostname: serveTaskOptions.host,
4848
port: serveTaskOptions.port.toString()
4949
});
50+
51+
if (serveTaskOptions.disableHostCheck) {
52+
ui.writeLine(oneLine`
53+
${chalk.yellow('WARNING')} Running a server with --disable-host-check is a security risk.
54+
See https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a
55+
for more information.
56+
`);
57+
}
58+
5059
let clientAddress = serverAddress;
51-
if (serveTaskOptions.liveReloadClient) {
52-
const clientUrl = url.parse(serveTaskOptions.liveReloadClient);
60+
if (serveTaskOptions.publicHost) {
61+
const clientUrl = url.parse(serveTaskOptions.publicHost);
5362
// very basic sanity check
5463
if (!clientUrl.host) {
5564
return Promise.reject(new SilentError(`'live-reload-client' must be a full URL.`));
@@ -94,7 +103,7 @@ export default Task.extend({
94103
webpackConfig.plugins.unshift({
95104
apply: (compiler: any) => {
96105
compiler.plugin('after-environment', () => {
97-
compiler.watchFileSystem = { watch: () => {} };
106+
compiler.watchFileSystem = { watch: () => { } };
98107
});
99108
}
100109
});
@@ -151,7 +160,9 @@ export default Task.extend({
151160
errors: serveTaskOptions.target === 'development',
152161
warnings: false
153162
},
154-
contentBase: false
163+
contentBase: false,
164+
public: serveTaskOptions.publicHost,
165+
disableHostCheck: serveTaskOptions.disableHostCheck
155166
};
156167

157168
if (sslKey != null && sslCert != null) {
@@ -185,7 +196,7 @@ export default Task.extend({
185196
return reject(err);
186197
}
187198
if (serveTaskOptions.open) {
188-
opn(serverAddress);
199+
opn(serverAddress);
189200
}
190201
});
191202
})

tests/e2e/tests/misc/live-reload.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export default function () {
104104
// Serve with live reload client set to api should call api.
105105
.then(_ => silentExecAndWaitForOutputToMatch(
106106
'ng',
107-
['e2e', '--watch', `--live-reload-client=${apiUrl}`],
107+
['e2e', '--watch', `--public-host=${apiUrl}`],
108108
protractorGoodRegEx
109109
))
110110
.then(_ => wait(2000))

tests/e2e/tests/misc/public-host.ts

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import * as os from 'os';
2+
import * as _ from 'lodash';
3+
4+
import { request } from '../../utils/http';
5+
import { killAllProcesses } from '../../utils/process';
6+
import { ngServe } from '../../utils/project';
7+
8+
export default function () {
9+
const firstLocalIp = _(os.networkInterfaces())
10+
.values()
11+
.flatten()
12+
.filter({ family: 'IPv4', internal: false })
13+
.map('address')
14+
.first();
15+
const publicHost = `${firstLocalIp}:4200`;
16+
const localAddress = `http://${publicHost}`;
17+
18+
return Promise.resolve()
19+
.then(() => ngServe('--host=0.0.0.0'))
20+
.then(() => request(localAddress))
21+
.then(body => {
22+
if (!body.match(/Invalid Host header/)) {
23+
throw new Error('Response does not match expected value.');
24+
}
25+
})
26+
.then(() => killAllProcesses(), (err) => { killAllProcesses(); throw err; })
27+
.then(() => ngServe('--host=0.0.0.0', `--public-host=${publicHost}`))
28+
.then(() => request(localAddress))
29+
.then(body => {
30+
if (!body.match(/<app-root>Loading...<\/app-root>/)) {
31+
throw new Error('Response does not match expected value.');
32+
}
33+
})
34+
.then(() => killAllProcesses(), (err) => { killAllProcesses(); throw err; })
35+
.then(() => ngServe('--host=0.0.0.0', `--disable-host-check`))
36+
.then(() => request(localAddress))
37+
.then(body => {
38+
if (!body.match(/<app-root>Loading...<\/app-root>/)) {
39+
throw new Error('Response does not match expected value.');
40+
}
41+
})
42+
.then(() => killAllProcesses(), (err) => { killAllProcesses(); throw err; });
43+
}

0 commit comments

Comments
 (0)