All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 46s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
147 lines
3.8 KiB
TypeScript
147 lines
3.8 KiB
TypeScript
import "./setup.ts";
|
|
import { assert, assertEquals, assertFalse, assertRejects } from "@std/assert";
|
|
import {
|
|
isPrivateAddress,
|
|
isPrivateHostname,
|
|
resolvePublicAddress,
|
|
} from "../lib/public-address.ts";
|
|
import { stubNetwork } from "./helpers.ts";
|
|
|
|
Deno.test("isPrivateAddress: private and reserved IPv4 ranges", () => {
|
|
for (
|
|
const ip of [
|
|
"0.0.0.0",
|
|
"10.1.2.3",
|
|
"127.0.0.1",
|
|
"100.64.0.1",
|
|
"100.127.255.255",
|
|
"169.254.169.254",
|
|
"172.16.0.1",
|
|
"172.31.255.255",
|
|
"192.0.0.8",
|
|
"192.168.1.1",
|
|
"198.18.0.1",
|
|
"224.0.0.1",
|
|
"255.255.255.255",
|
|
]
|
|
) {
|
|
assert(isPrivateAddress(ip), ip);
|
|
}
|
|
});
|
|
|
|
Deno.test("isPrivateAddress: public IPv4 addresses", () => {
|
|
for (
|
|
const ip of [
|
|
"8.8.8.8",
|
|
"93.184.216.34",
|
|
"100.63.255.255",
|
|
"100.128.0.0",
|
|
"172.15.255.255",
|
|
"172.32.0.0",
|
|
"192.169.0.1",
|
|
"223.255.255.255",
|
|
]
|
|
) {
|
|
assertFalse(isPrivateAddress(ip), ip);
|
|
}
|
|
});
|
|
|
|
Deno.test("isPrivateAddress: IPv6, including IPv4 carried inside it", () => {
|
|
for (
|
|
const ip of [
|
|
"::",
|
|
"::1",
|
|
"fc00::1",
|
|
"fd12:3456::1",
|
|
"fe80::1%eth0",
|
|
"fec0::1",
|
|
"ff02::1",
|
|
"::ffff:127.0.0.1",
|
|
"::ffff:7f00:1",
|
|
"::ffff:10.0.0.1",
|
|
"64:ff9b::a00:1", // NAT64 of 10.0.0.1
|
|
"2002:a00:1::", // 6to4 of 10.0.0.1
|
|
"::10.0.0.1",
|
|
]
|
|
) {
|
|
assert(isPrivateAddress(ip), ip);
|
|
}
|
|
for (
|
|
const ip of [
|
|
"2606:4700:4700::1111",
|
|
"::ffff:8.8.8.8",
|
|
"64:ff9b::808:808",
|
|
"2002:808:808::",
|
|
]
|
|
) {
|
|
assertFalse(isPrivateAddress(ip), ip);
|
|
}
|
|
});
|
|
|
|
Deno.test("isPrivateAddress: anything that isn't an IP is not an address", () => {
|
|
for (
|
|
const s of ["example.com", "1.2.3", "1.2.3.4.5", "256.1.1.1", "1::2::3", ""]
|
|
) {
|
|
assertFalse(isPrivateAddress(s), s);
|
|
}
|
|
});
|
|
|
|
Deno.test("isPrivateHostname: localhost names and bracketed literals", () => {
|
|
assert(isPrivateHostname(new URL("http://localhost:8000/")));
|
|
assert(isPrivateHostname(new URL("http://app.localhost/")));
|
|
assert(isPrivateHostname(new URL("http://[::1]/")));
|
|
assert(isPrivateHostname(new URL("http://127.0.0.1/")));
|
|
// WHATWG URL parsing normalises these to 127.0.0.1 before we see them.
|
|
assert(isPrivateHostname(new URL("http://0x7f000001/")));
|
|
assert(isPrivateHostname(new URL("http://2130706433/")));
|
|
assertFalse(isPrivateHostname(new URL("https://example.com/")));
|
|
});
|
|
|
|
Deno.test("resolvePublicAddress: IP literals skip DNS", async () => {
|
|
using net = stubNetwork(() => new Response());
|
|
assertEquals(
|
|
await resolvePublicAddress(new URL("https://8.8.8.8/")),
|
|
"8.8.8.8",
|
|
);
|
|
assertEquals(
|
|
await resolvePublicAddress(new URL("https://[2606:4700::1]/")),
|
|
"2606:4700::1",
|
|
);
|
|
assertEquals(net.calls.length, 0);
|
|
});
|
|
|
|
Deno.test("resolvePublicAddress: refuses private literals without resolving", async () => {
|
|
await assertRejects(
|
|
() => resolvePublicAddress(new URL("http://169.254.169.254/latest")),
|
|
Error,
|
|
"private",
|
|
);
|
|
});
|
|
|
|
Deno.test("resolvePublicAddress: a name resolving anywhere private is refused", async () => {
|
|
using _ = stubNetwork(() => new Response(), {
|
|
"internal.example": ["10.0.0.5"],
|
|
"mixed.example": ["93.184.216.34", "127.0.0.1"],
|
|
"nowhere.example": [],
|
|
});
|
|
await assertRejects(
|
|
() => resolvePublicAddress(new URL("http://internal.example/")),
|
|
Error,
|
|
"resolves to 10.0.0.5",
|
|
);
|
|
await assertRejects(
|
|
() => resolvePublicAddress(new URL("http://mixed.example/")),
|
|
Error,
|
|
"resolves to 127.0.0.1",
|
|
);
|
|
await assertRejects(
|
|
() => resolvePublicAddress(new URL("http://nowhere.example/")),
|
|
Error,
|
|
"Could not resolve",
|
|
);
|
|
assertEquals(
|
|
await resolvePublicAddress(new URL("http://public.example/")),
|
|
"93.184.216.34",
|
|
);
|
|
});
|