From 0a33e6a7529ef20ec8841c3fd501c37da179be3e Mon Sep 17 00:00:00 2001 From: Jon Dufresne Date: Mon, 5 Sep 2022 09:51:10 -0700 Subject: [PATCH] feat: make allowedHosts accept localhost subdomains by default (#4357) --- lib/Server.js | 4 +- .../allowed-hosts.test.js.snap.webpack4 | 6 +++ .../allowed-hosts.test.js.snap.webpack5 | 6 +++ test/e2e/allowed-hosts.test.js | 41 +++++++++++++++++++ 4 files changed, 56 insertions(+), 1 deletion(-) diff --git a/lib/Server.js b/lib/Server.js index 1dc2e0b7a3..057d5ad40b 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -2987,12 +2987,14 @@ class Server { // an IPv6-address in URLs, // these are removed from the hostname in url.parse(), // so we have the pure IPv6-address in hostname. - // always allow localhost host, for convenience (hostname === 'localhost') + // For convenience, always allow localhost (hostname === 'localhost') + // and its subdomains (hostname.endsWith(".localhost")). // allow hostname of listening address (hostname === this.options.host) const isValidHostname = (hostname !== null && ipaddr.IPv4.isValid(hostname)) || (hostname !== null && ipaddr.IPv6.isValid(hostname)) || hostname === "localhost" || + (hostname !== null && hostname.endsWith(".localhost")) || hostname === this.options.host; if (isValidHostname) { diff --git a/test/e2e/__snapshots__/allowed-hosts.test.js.snap.webpack4 b/test/e2e/__snapshots__/allowed-hosts.test.js.snap.webpack4 index 83b7fe5073..1bd829b500 100644 --- a/test/e2e/__snapshots__/allowed-hosts.test.js.snap.webpack4 +++ b/test/e2e/__snapshots__/allowed-hosts.test.js.snap.webpack4 @@ -18,6 +18,12 @@ exports[`allowed hosts check host headers should always allow \`localhost\` if o exports[`allowed hosts check host headers should always allow \`localhost\` if options.allowedHosts is auto: response status 1`] = `200`; +exports[`allowed hosts check host headers should always allow \`localhost\` subdomain if options.allowedHosts is auto: console messages 1`] = `Array []`; + +exports[`allowed hosts check host headers should always allow \`localhost\` subdomain if options.allowedHosts is auto: page errors 1`] = `Array []`; + +exports[`allowed hosts check host headers should always allow \`localhost\` subdomain if options.allowedHosts is auto: response status 1`] = `200`; + exports[`allowed hosts check host headers should always allow any host if options.allowedHosts is all: console messages 1`] = `Array []`; exports[`allowed hosts check host headers should always allow any host if options.allowedHosts is all: page errors 1`] = `Array []`; diff --git a/test/e2e/__snapshots__/allowed-hosts.test.js.snap.webpack5 b/test/e2e/__snapshots__/allowed-hosts.test.js.snap.webpack5 index 83b7fe5073..1bd829b500 100644 --- a/test/e2e/__snapshots__/allowed-hosts.test.js.snap.webpack5 +++ b/test/e2e/__snapshots__/allowed-hosts.test.js.snap.webpack5 @@ -18,6 +18,12 @@ exports[`allowed hosts check host headers should always allow \`localhost\` if o exports[`allowed hosts check host headers should always allow \`localhost\` if options.allowedHosts is auto: response status 1`] = `200`; +exports[`allowed hosts check host headers should always allow \`localhost\` subdomain if options.allowedHosts is auto: console messages 1`] = `Array []`; + +exports[`allowed hosts check host headers should always allow \`localhost\` subdomain if options.allowedHosts is auto: page errors 1`] = `Array []`; + +exports[`allowed hosts check host headers should always allow \`localhost\` subdomain if options.allowedHosts is auto: response status 1`] = `200`; + exports[`allowed hosts check host headers should always allow any host if options.allowedHosts is all: console messages 1`] = `Array []`; exports[`allowed hosts check host headers should always allow any host if options.allowedHosts is all: page errors 1`] = `Array []`; diff --git a/test/e2e/allowed-hosts.test.js b/test/e2e/allowed-hosts.test.js index aeb5b7a78d..bc13801102 100644 --- a/test/e2e/allowed-hosts.test.js +++ b/test/e2e/allowed-hosts.test.js @@ -1209,6 +1209,47 @@ describe("allowed hosts", () => { expect(pageErrors).toMatchSnapshot("page errors"); }); + it("should always allow `localhost` subdomain if options.allowedHosts is auto", async () => { + const options = { + allowedHosts: "auto", + port: port1, + }; + + const headers = { + host: "app.localhost", + }; + + server = new Server(options, compiler); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port1}/main.js`, { + waitUntil: "networkidle0", + }); + + if (!server.checkHeader(headers, "host")) { + throw new Error("Validation didn't fail"); + } + + expect(response.status()).toMatchSnapshot("response status"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + it("should always allow value from the `host` options if options.allowedHosts is auto", async () => { const networkIP = Server.internalIPSync("v4"); const options = {