Skip to content

Commit ab889c3

Browse files
orteth01shellscape
authored andcommitted
Add 'allowedHosts' option (#899)
* Add 'allowedHosts' option * add support for subdomain wildcard in 'allowedHosts' option * add tests for allowedHosts
1 parent 1a26ab4 commit ab889c3

File tree

3 files changed

+70
-1
lines changed

3 files changed

+70
-1
lines changed

lib/Server.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ function Server(compiler, options) {
4040
this.clientOverlay = options.overlay;
4141
this.disableHostCheck = !!options.disableHostCheck;
4242
this.publicHost = options.public;
43+
this.allowedHosts = options.allowedHosts;
4344
this.sockets = [];
4445
this.contentBaseWatchers = [];
4546

@@ -443,6 +444,21 @@ Server.prototype.checkHost = function(headers) {
443444
// always allow localhost host, for convience
444445
if(hostname === "127.0.0.1" || hostname === "localhost") return true;
445446

447+
// allow if hostname is in allowedHosts
448+
if(this.allowedHosts && this.allowedHosts.length) {
449+
for(let hostIdx = 0; hostIdx < this.allowedHosts.length; hostIdx++) {
450+
const allowedHost = this.allowedHosts[hostIdx];
451+
if(allowedHost === hostname) return true;
452+
453+
// support "." as a subdomain wildcard
454+
// e.g. ".example.com" will allow "example.com", "www.example.com", "subdomain.example.com", etc
455+
if(allowedHost[0] === ".") {
456+
if(hostname === allowedHost.substring(1)) return true; // "example.com"
457+
if(hostname.endsWith(allowedHost)) return true; // "*.example.com"
458+
}
459+
}
460+
}
461+
446462
// allow hostname of listening adress
447463
if(hostname === this.listenHostname) return true;
448464

lib/optionsSchema.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@
1717
"description": "The host the server listens to.",
1818
"type": "string"
1919
},
20+
"allowedHosts": {
21+
"description": "Specifies which hosts are allowed to access the dev server.",
22+
"items": {
23+
"type": "string"
24+
},
25+
"type": "array"
26+
},
2027
"filename": {
2128
"description": "The filename that needs to be requested in order to trigger a recompile (only in lazy mode).",
2229
"anyOf": [

test/Validation.test.js

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ describe("Validation", function() {
2222
message: [
2323
" - configuration.public should be a string."
2424
]
25+
}, {
26+
name: "invalid `allowedHosts` configuration",
27+
config: { allowedHosts: 1 },
28+
message: [
29+
" - configuration.allowedHosts should be an array:",
30+
" [string]",
31+
" Specifies which hosts are allowed to access the dev server."
32+
]
2533
}, {
2634
name: "invalid `contentBase` configuration",
2735
config: { contentBase: [0] },
@@ -40,7 +48,7 @@ describe("Validation", function() {
4048
config: { asdf: true },
4149
message: [
4250
" - configuration has an unknown property 'asdf'. These properties are valid:",
43-
" object { hot?, hotOnly?, lazy?, host?, filename?, publicPath?, port?, socket?, " +
51+
" object { hot?, hotOnly?, lazy?, host?, allowedHosts?, filename?, publicPath?, port?, socket?, " +
4452
"watchOptions?, headers?, clientLogLevel?, overlay?, key?, cert?, ca?, pfx?, pfxPassphrase?, " +
4553
"inline?, disableHostCheck?, public?, https?, contentBase?, watchContentBase?, open?, features?, " +
4654
"compress?, proxy?, historyApiFallback?, staticOptions?, setup?, stats?, reporter?, " +
@@ -115,5 +123,43 @@ describe("Validation", function() {
115123
throw new Error("Validation didn't fail");
116124
}
117125
});
126+
127+
describe("allowedHosts", function() {
128+
it("should allow hosts in allowedHosts", function() {
129+
const testHosts = [
130+
"test.host",
131+
"test2.host",
132+
"test3.host"
133+
];
134+
const options = { allowedHosts: testHosts };
135+
const server = new Server(compiler, options);
136+
137+
testHosts.forEach(function(testHost) {
138+
const headers = { host: testHost };
139+
if(!server.checkHost(headers)) {
140+
throw new Error("Validation didn't fail");
141+
}
142+
});
143+
});
144+
it("should allow hosts that pass a wildcard in allowedHosts", function() {
145+
const options = { allowedHosts: [".example.com"] };
146+
const server = new Server(compiler, options);
147+
const testHosts = [
148+
"www.example.com",
149+
"subdomain.example.com",
150+
"example.com",
151+
"subsubcomain.subdomain.example.com",
152+
"example.com:80",
153+
"subdomain.example.com:80"
154+
];
155+
156+
testHosts.forEach(function(testHost) {
157+
const headers = { host: testHost };
158+
if(!server.checkHost(headers)) {
159+
throw new Error("Validation didn't fail");
160+
}
161+
});
162+
});
163+
});
118164
})
119165
});

0 commit comments

Comments
 (0)