mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
Vite installs its Host check after the middleware plugins add in configureServer, so the provider and /api routes answered any Host, including a DNS-rebinding name. hostCheckPlugin runs first on the dev and preview servers and applies Vite's rule with the same allowed hosts: IP addresses, localhost and *.localhost, the configured server host, and the listed names. A test drives a real Vite server with an unlisted Host. Co-Authored-By: Claude Opus 5.5 <[email protected]>
154 lines
4.5 KiB
JavaScript
154 lines
4.5 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { request as httpRequest } from 'node:http';
|
|
import { fileURLToPath } from 'node:url';
|
|
import {
|
|
DEFAULT_ALLOWED_HOSTS,
|
|
hostCheckPlugin,
|
|
isAllowedHost,
|
|
resolveAllowedHosts,
|
|
} from '../../build/allowedHosts.js';
|
|
|
|
test('uses the restricted local host allowlist by default', () => {
|
|
assert.deepEqual(resolveAllowedHosts(), DEFAULT_ALLOWED_HOSTS);
|
|
assert.equal(resolveAllowedHosts().includes(true), false);
|
|
});
|
|
|
|
test('adds explicitly configured LAN hostnames without widening the allowlist', () => {
|
|
assert.deepEqual(
|
|
resolveAllowedHosts('globe.lan, globe.internal ,globe.lan'),
|
|
['localhost', '127.0.0.1', 'globe.lan', 'globe.internal'],
|
|
);
|
|
});
|
|
|
|
test('ignores empty configured host entries', () => {
|
|
assert.deepEqual(resolveAllowedHosts(' , , globe.lan, '), [
|
|
'localhost',
|
|
'127.0.0.1',
|
|
'globe.lan',
|
|
]);
|
|
});
|
|
|
|
test('rejects suffix and wildcard entries so every LAN hostname is explicit', () => {
|
|
assert.deepEqual(resolveAllowedHosts('.local,*.example,globe.lan'), [
|
|
'localhost',
|
|
'127.0.0.1',
|
|
'globe.lan',
|
|
]);
|
|
});
|
|
|
|
test('a Host is allowed by the same rule Vite applies', () => {
|
|
const allowed = ['localhost', '127.0.0.1', 'globe.lan', '.corp.example'];
|
|
for (const host of [
|
|
'localhost:4173',
|
|
'LOCALHOST:4173',
|
|
'app.localhost',
|
|
'127.0.0.1:4173',
|
|
'192.168.1.20:4173',
|
|
'[::1]:4173',
|
|
'globe.lan:4173',
|
|
'corp.example',
|
|
'a.corp.example:8080',
|
|
'office:4173',
|
|
])
|
|
assert.equal(isAllowedHost(host, allowed, ['office']), true, host);
|
|
for (const host of [
|
|
undefined,
|
|
'',
|
|
'evil.example:4173',
|
|
'globe.lan.evil.example',
|
|
'localhost.evil.example',
|
|
'mybox.local:4173',
|
|
'[not-an-ip]:4173',
|
|
])
|
|
assert.equal(isAllowedHost(host, allowed, ['office']), false, String(host));
|
|
assert.equal(isAllowedHost('anything.example', true), true);
|
|
});
|
|
|
|
test('the Host check is installed first on the dev and preview servers', () => {
|
|
const plugin = hostCheckPlugin();
|
|
assert.equal(plugin.enforce, 'pre');
|
|
for (const hook of ['configureServer', 'configurePreviewServer']) {
|
|
let middleware;
|
|
plugin[hook]({
|
|
config: {
|
|
server: { allowedHosts: ['localhost'], host: 'localhost' },
|
|
preview: { allowedHosts: ['localhost'], host: undefined },
|
|
},
|
|
middlewares: { use: (fn) => (middleware = fn) },
|
|
});
|
|
const respond = (host) => {
|
|
const res = {
|
|
status: null,
|
|
writeHead(status) {
|
|
this.status = status;
|
|
},
|
|
end() {},
|
|
};
|
|
let passed = false;
|
|
middleware({ headers: { host } }, res, () => (passed = true));
|
|
return passed ? 'next' : res.status;
|
|
};
|
|
assert.equal(respond('localhost:4173'), 'next', hook);
|
|
assert.equal(respond('evil.example:4173'), 403, hook);
|
|
}
|
|
});
|
|
|
|
test('an unlisted Host cannot reach a route a plugin mounts', async (t) => {
|
|
const { createServer } = await import('vite');
|
|
const { createBrowserViteConfig } = await import('../../build/vite.js');
|
|
const provider = {
|
|
name: 'fixture-provider',
|
|
configureServer(server) {
|
|
server.middlewares.use('/api/fixture', (req, res) => {
|
|
res.end('provider answered');
|
|
});
|
|
},
|
|
};
|
|
const base = createBrowserViteConfig({ plugins: [provider] });
|
|
const vite = await createServer({
|
|
...base,
|
|
root: fileURLToPath(new URL('../../', import.meta.url)),
|
|
configFile: false,
|
|
envFile: false,
|
|
publicDir: false,
|
|
logLevel: 'silent',
|
|
// Only this test's plugins: the Host check and the fixture provider.
|
|
plugins: base.plugins.filter((plugin) =>
|
|
['host-check', 'fixture-provider'].includes(plugin?.name),
|
|
),
|
|
optimizeDeps: { noDiscovery: true, include: [] },
|
|
server: {
|
|
...base.server,
|
|
host: '127.0.0.1',
|
|
port: 0,
|
|
hmr: false,
|
|
watch: null,
|
|
},
|
|
});
|
|
await vite.listen();
|
|
t.after(() => vite.close());
|
|
const { port } = vite.httpServer.address();
|
|
const get = (host) =>
|
|
new Promise((resolve, reject) => {
|
|
const request = httpRequest(
|
|
{
|
|
host: '127.0.0.1',
|
|
port,
|
|
path: '/api/fixture',
|
|
headers: { Host: host },
|
|
},
|
|
(response) => {
|
|
response.resume();
|
|
resolve(response.statusCode);
|
|
},
|
|
);
|
|
request.on('error', reject);
|
|
request.end();
|
|
});
|
|
assert.equal(await get(`localhost:${port}`), 200);
|
|
assert.equal(await get(`127.0.0.1:${port}`), 200);
|
|
assert.equal(await get(`evil.example:${port}`), 403);
|
|
assert.equal(await get(`mybox.local:${port}`), 403);
|
|
});
|