Improve localhost detection

This commit is contained in:
Rūdolfs Ošiņš
2026-01-17 09:35:54 -06:00
parent 8f52b2bdfb
commit ebe4e426e8
2 changed files with 59 additions and 16 deletions
+13 -2
View File
@@ -204,8 +204,19 @@ export function isMarkdownPath(path: string): boolean {
}
export function isLocal(addr: string): boolean {
// Support *.localhost subdomains and 127.0.0.1.
return addr.endsWith("localhost") || addr.startsWith("127.0.0.1");
try {
const url = new URL(`scheme://${addr}`);
const hostname = url.hostname;
return (
hostname === "[::1]" ||
hostname === "127.0.0.1" ||
hostname === "localhost" ||
hostname.endsWith(".localhost")
);
} catch {
return false;
}
}
// Check whether the given domain name is an onion domain name.
+46 -14
View File
@@ -236,21 +236,53 @@ describe("Date Manipulation", () => {
});
describe("isLocal", () => {
test("returns true for localhost", () => {
expect(utils.isLocal("localhost")).toBe(true);
describe("returns true for valid local addresses", () => {
test.each([
{ addr: "localhost", description: "bare localhost" },
{ addr: "app.localhost", description: "localhost subdomain" },
{
addr: "deeper.app.localhost",
description: "nested localhost subdomain",
},
{
addr: "deeper.app.localhost:8080",
description: "nested localhost subdomain with port",
},
{ addr: "127.0.0.1", description: "IPv4 loopback" },
{ addr: "127.0.0.1:8080", description: "IPv4 loopback with port" },
{ addr: "[::1]", description: "IPv6 loopback" },
{
addr: "localhost:3000",
description: "localhost with port",
},
])("$description: $addr", ({ addr }) => {
expect(utils.isLocal(addr)).toBe(true);
});
});
test("returns true for 127.0.0.1", () => {
expect(utils.isLocal("127.0.0.1")).toBe(true);
});
test("returns true for localhost subdomains", () => {
expect(utils.isLocal("test.localhost")).toBe(true);
expect(utils.isLocal("deeper.test.localhost")).toBe(true);
});
test("returns false for any other tld", () => {
expect(utils.isLocal("example.com")).toBe(false);
expect(utils.isLocal("radicle.garden")).toBe(false);
describe("returns false for invalid/remote addresses", () => {
test.each([
{ addr: "example.com", description: "remote domain" },
{
addr: "notlocalhost",
description: "domain that ends with 'localhost'",
},
{
addr: "127.0.0.1.evil.com",
description: "malicious domain mimicking loopback",
},
{ addr: "192.168.1.1", description: "private network IP" },
{ addr: "10.0.0.1", description: "another private network IP" },
{ addr: "", description: "empty string" },
{ addr: "not a url", description: "invalid URL format" },
{ addr: "localhost.com", description: "domain with localhost in name" },
{ addr: "mylocalhost.com", description: "domain containing localhost" },
{
addr: "http://example.com",
description: "remote domain with scheme",
},
])("$description: $addr", ({ addr }) => {
expect(utils.isLocal(addr)).toBe(false);
});
});
});