1import { describe, expect, it } from "vite-plus/test";
2
3import { isPublicFaviconHost } from "./hostClassification.ts";
4
5describe("isPublicFaviconHost", () => {
6 it("treats public hosts as public", () => {
7 for (const host of [
8 "github.com",
9 "www.google.com",
10 "t3.chat",
11 "sub.domain.example.co.uk",
12 "8.8.8.8",
13 "1.1.1.1",
14 "100.200.1.1",
15 "172.32.0.1",
16 "192.167.1.1",
17 "11.0.0.1",
18 ]) {
19 expect(isPublicFaviconHost(host), host).toBe(true);
20 }
21 });
22
23 it("detects private IPv4 ranges", () => {
24 for (const host of [
25 "0.0.0.0",
26 "10.0.0.1",
27 "10.255.255.255",
28 "127.0.0.1",
29 "192.168.1.10",
30 "172.16.0.1",
31 "172.31.255.255",
32 "169.254.1.1",
33 ]) {
34 expect(isPublicFaviconHost(host), host).toBe(false);
35 }
36 });
37
38 it("detects the Tailscale 100.64.0.0/10 range", () => {
39 for (const host of ["100.64.0.1", "100.100.100.100", "100.126.17.15", "100.127.255.255"]) {
40 expect(isPublicFaviconHost(host), host).toBe(false);
41 }
42 expect(isPublicFaviconHost("100.63.255.255")).toBe(true);
43 expect(isPublicFaviconHost("100.128.0.1")).toBe(true);
44 });
45
46 it("detects private host names and suffixes", () => {
47 for (const host of [
48 "localhost",
49 "air",
50 "printer.local",
51 "api.internal",
52 "router.home.arpa",
53 "home.arpa",
54 "box.tailnet.ts.net",
55 "AIR.TAILE8BEA7.TS.NET",
56 ]) {
57 expect(isPublicFaviconHost(host), host).toBe(false);
58 }
59 });
60
61 it("detects private IPv6 addresses", () => {
62 for (const host of ["::1", "[::1]", "fd00::1", "fc00::1", "fe80::1", "FD12:3456::1"]) {
63 expect(isPublicFaviconHost(host), host).toBe(false);
64 }
65 expect(isPublicFaviconHost("2606:4700:4700::1111")).toBe(true);
66 });
67
68 it("detects IPv4-mapped IPv6 addresses in both spellings", () => {
69 for (const host of [
70 "::ffff:192.168.1.10",
71 "::ffff:10.0.0.1",
72 "::ffff:100.126.17.15",
73 "[::ffff:192.168.1.10]",
74 // c0a8:010a is 192.168.1.10, 0a00:0001 is 10.0.0.1.
75 "::ffff:c0a8:010a",
76 "::ffff:a00:1",
77 ]) {
78 expect(isPublicFaviconHost(host), host).toBe(false);
79 }
80 expect(isPublicFaviconHost("::ffff:8.8.8.8")).toBe(true);
81 expect(isPublicFaviconHost("::ffff:808:808")).toBe(true);
82 });
83
84 it("ignores a trailing DNS root label", () => {
85 for (const host of [
86 "localhost.",
87 "printer.local.",
88 "api.internal.",
89 "box.tailnet.ts.net.",
90 "air.",
91 ]) {
92 expect(isPublicFaviconHost(host), host).toBe(false);
93 }
94 expect(isPublicFaviconHost("github.com.")).toBe(true);
95 });
96
97 it("detects names under .localhost", () => {
98 for (const host of ["app.localhost", "api.app.localhost", "APP.LOCALHOST"]) {
99 expect(isPublicFaviconHost(host), host).toBe(false);
100 }
101 });
102
103 it("treats an empty host as private", () => {
104 expect(isPublicFaviconHost("")).toBe(false);
105 expect(isPublicFaviconHost(" ")).toBe(false);
106 });
107
108 it("rejects malformed IPv4 text as a public host", () => {
109 expect(isPublicFaviconHost("10.0.0.999")).toBe(true);
110 expect(isPublicFaviconHost("10.0.0")).toBe(true);
111 });
112});