fix(gateway): harden canvas auth with session capabilities

This commit is contained in:
Peter Steinberger
2026-02-19 15:50:42 +01:00
parent f76f98b268
commit c45f3c5b00
11 changed files with 353 additions and 126 deletions

View File

@@ -5,6 +5,7 @@ import {
isSecureWebSocketUrl,
isTrustedProxyAddress,
pickPrimaryLanIPv4,
resolveGatewayClientIp,
resolveGatewayListenHosts,
resolveHostName,
} from "./net.js";
@@ -131,6 +132,43 @@ describe("isTrustedProxyAddress", () => {
});
});
describe("resolveGatewayClientIp", () => {
it("returns remote IP when the remote is not a trusted proxy", () => {
const ip = resolveGatewayClientIp({
remoteAddr: "203.0.113.10",
forwardedFor: "10.0.0.2",
trustedProxies: ["127.0.0.1"],
});
expect(ip).toBe("203.0.113.10");
});
it("returns forwarded client IP when the remote is a trusted proxy", () => {
const ip = resolveGatewayClientIp({
remoteAddr: "127.0.0.1",
forwardedFor: "10.0.0.2, 127.0.0.1",
trustedProxies: ["127.0.0.1"],
});
expect(ip).toBe("10.0.0.2");
});
it("fails closed when trusted proxy headers are missing", () => {
const ip = resolveGatewayClientIp({
remoteAddr: "127.0.0.1",
trustedProxies: ["127.0.0.1"],
});
expect(ip).toBeUndefined();
});
it("supports IPv6 client IP forwarded by a trusted proxy", () => {
const ip = resolveGatewayClientIp({
remoteAddr: "127.0.0.1",
realIp: "[2001:db8::5]",
trustedProxies: ["127.0.0.1"],
});
expect(ip).toBe("2001:db8::5");
});
});
describe("resolveGatewayListenHosts", () => {
it("returns the input host when not loopback", async () => {
const hosts = await resolveGatewayListenHosts("0.0.0.0", {