Something went wrong. Try again.
Monorepo for Tangled forked from tangled.org/core
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125import { describe, expect, it, vi } from "vitest";import { fetchPublic, isPublicHost, isPublicUrl, publicOnly, readTextCapped, UnsafeTargetError} from "#lib/publicFetch.ts";
const prod = false;
describe("isPublicHost", () => { it("allows public names", () => { expect(isPublicHost("bsky.social")).toBe(true); expect(isPublicHost("pds.tngl.boltless.dev")).toBe(true); });
it("blocks ip literals, service names and internal suffixes", () => { for (const host of [ "127.0.0.1", "169.254.169.254", "[::1]", "localhost", "bobbin", "metadata.google.internal", "app.localhost", "nas.local", "vm.home.arpa", "" ]) expect(isPublicHost(host), host).toBe(false); });
it("treats a trailing dot as the same name", () => { expect(isPublicHost("localhost.")).toBe(false); expect(isPublicHost("metadata.google.internal.")).toBe(false); });});
describe("isPublicUrl", () => { it("needs https outside dev", () => { expect(isPublicUrl(new URL("https://pds.example.com"), prod)).toBe(true); expect(isPublicUrl(new URL("http://pds.example.com"), prod)).toBe(false); // the url parser normalises numeric hosts to dotted ipv4 expect(isPublicUrl(new URL("https://2130706433"), prod)).toBe(false); });
it("lets anything through in dev", () => { expect(isPublicUrl(new URL("http://localhost:2583"), true)).toBe(true); });});
const redirect = (to: string) => new Response(null, { status: 302, headers: { location: to } });
describe("fetchPublic", () => { it("refuses a private target without fetching", async () => { const fetch = vi.fn(); await expect( fetchPublic(fetch, "http://127.0.0.1:8090/x", {}, prod) ).rejects.toBeInstanceOf(UnsafeTargetError); expect(fetch).not.toHaveBeenCalled(); });
it("follows a redirect to another public host", async () => { const fetch = vi .fn() .mockResolvedValueOnce(redirect("https://cdn.example.com/blob")) .mockResolvedValueOnce(new Response("ok")); const res = await fetchPublic(fetch, "https://pds.example.com/x", {}, prod); expect(await res.text()).toBe("ok"); expect(fetch.mock.calls.map(([u]) => String(u))).toEqual([ "https://pds.example.com/x", "https://cdn.example.com/blob" ]); expect(fetch.mock.calls[0][1]).toMatchObject({ redirect: "manual" }); });
it("refuses a redirect into the private network", async () => { const fetch = vi.fn().mockResolvedValueOnce(redirect("http://169.254.169.254/latest")); await expect( fetchPublic(fetch, "https://pds.example.com/x", {}, prod) ).rejects.toBeInstanceOf(UnsafeTargetError); expect(fetch).toHaveBeenCalledTimes(1); });
it("gives up on a redirect loop", async () => { const fetch = vi.fn(() => Promise.resolve(redirect("https://pds.example.com/x"))); await expect(fetchPublic(fetch, "https://pds.example.com/x", {}, prod)).rejects.toThrow( /too many redirects/ ); });});
describe("publicOnly", () => { it("rejects private targets and forbids redirects for the rest", async () => { const fetch = vi.fn(() => Promise.resolve(new Response("ok"))); const guarded = publicOnly(fetch, prod); await expect(guarded("http://10.0.0.5:9000/xrpc/x")).rejects.toBeInstanceOf( UnsafeTargetError ); await guarded("https://spindle.example.com/xrpc/x"); expect(fetch).toHaveBeenCalledTimes(1); expect(fetch.mock.calls[0]).toEqual([ "https://spindle.example.com/xrpc/x", { redirect: "error" } ]); });});
describe("readTextCapped", () => { it("reads a body under the cap", async () => { expect(await readTextCapped(new Response("héllo"), 100)).toBe("héllo"); });
it("fails past the cap, declared or streamed", async () => { await expect( readTextCapped(new Response("x", { headers: { "content-length": "999" } }), 10) ).rejects.toThrow(/over 10 bytes/); await expect(readTextCapped(new Response("x".repeat(50)), 10)).rejects.toThrow( /over 10 bytes/ ); });});