feat(gateway): allow secured LAN console access

This commit is contained in:
chick
2026-07-18 19:47:23 +08:00
parent e390069edb
commit d575ab4d9d
4 changed files with 133 additions and 6 deletions
+57 -1
View File
@@ -117,6 +117,61 @@ describe('same-origin canary gateway', () => {
/loopback/i,
);
}
expect(() =>
createCanaryGateway({
distDir: '/tmp/dist',
host: '0.0.0.0',
port: 8788,
ownsProductionPort: true,
allowedHosts: ['0.0.0.0'],
}),
).toThrow(/invalid allowed gateway host/i);
expect(() =>
createCanaryGateway({
distDir: '/tmp/dist',
host: '0.0.0.0',
port: 8788,
ownsProductionPort: true,
allowedHosts: ['00.00.00.00'],
}),
).toThrow(/invalid allowed gateway host/i);
});
it('allows an explicit production LAN bind with an exact Host allowlist', async () => {
const upstream = createServer((_request, response) => response.end('upstream reached'));
servers.push(upstream);
const gateway = createCanaryGateway({
distDir: await fixtureDist(),
host: '0.0.0.0',
port: 0,
upstreamPort: await listen(upstream),
ownsProductionPort: true,
allowedHosts: ['192.168.2.69'],
});
gateways.push(gateway);
await gateway.start();
const allowed = await rawRequest(gateway.origin, '/', { host: '192.168.2.69:0' });
expect(allowed.status).toBe(200);
const denied = await rawRequest(gateway.origin, '/', { host: 'evil.test:0' });
expect(denied.status).toBe(400);
const wildcardHost = await rawRequest(gateway.origin, '/', { host: '0.0.0.0:0' });
expect(wildcardHost.status).toBe(400);
const wildcardOrigin = await rawRequest(gateway.origin, '/api/v1/instances', {
host: '192.168.2.69:0',
origin: 'http://0.0.0.0:0',
});
expect(wildcardOrigin.status).toBe(403);
const foreignOrigin = await rawRequest(gateway.origin, '/api/v1/instances', {
host: '192.168.2.69:0',
origin: 'https://evil.example',
});
expect(foreignOrigin.status).toBe(403);
const allowedOrigin = await rawRequest(gateway.origin, '/api/v1/instances', {
host: '192.168.2.69:0',
origin: 'http://192.168.2.69:0',
});
expect(allowedOrigin.status).toBe(200);
});
it('rejects missing, malformed, and foreign authority before serving or proxying', async () => {
@@ -253,9 +308,10 @@ describe('same-origin canary gateway', () => {
'/healthz',
'/readyz',
]);
const upstreamOrigin = `http://127.0.0.1:${upstreamPort}`;
expect(
seen.every(
({ host, origin }) => host === new URL(browserOrigin).host && origin === browserOrigin,
({ host, origin }) => host === `127.0.0.1:${upstreamPort}` && origin === upstreamOrigin,
),
).toBe(true);
expect(seen.every(({ custom }) => custom === undefined)).toBe(true);