From daa13c808bc6a29d1d3f067bb7e2d47a970eaee8 Mon Sep 17 00:00:00 2001 From: Hendrik Date: Fri, 15 May 2026 16:48:07 +0200 Subject: [PATCH] Fix admin UI inaccessible via private/local IP isAdminHost() only matched localhost and the configured server_ip (set to the public IP by the install script). Installations accessed via RFC 1918 addresses (10.x, 192.168.x, 172.16-31.x) fell through to the redirect-domain handler and returned 'Domain nicht konfiguriert'. Extract isPrivateOrLoopbackIp() to recognize all private and loopback addresses as admin hosts. No security risk: redirect domains are never private IPs. --- lib/redirect-resolver.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/redirect-resolver.ts b/lib/redirect-resolver.ts index 8975cfe..5a9ea0b 100644 --- a/lib/redirect-resolver.ts +++ b/lib/redirect-resolver.ts @@ -50,11 +50,20 @@ export function resolveHost(host: string): ResolvedRedirect | null { return cache.get(host.toLowerCase()) ?? null; } +function isPrivateOrLoopbackIp(h: string): boolean { + if (h === "localhost" || h === "127.0.0.1" || h === "::1") return true; + // RFC 1918 — never used as redirect domains + if (/^10\./.test(h)) return true; + if (/^192\.168\./.test(h)) return true; + if (/^172\.(1[6-9]|2[0-9]|3[01])\./.test(h)) return true; + return false; +} + export function isAdminHost(host: string): boolean { const baseDomain = getSetting("base_domain"); const serverIp = getSetting("server_ip"); const h = host.toLowerCase().split(":")[0]; - if (h === "localhost" || h === "127.0.0.1" || h === "::1") return true; + if (isPrivateOrLoopbackIp(h)) return true; if (baseDomain && h === baseDomain.toLowerCase()) return true; if (serverIp && h === serverIp) return true; return false;