import { describe, expect, it, vi } from "vitest"; import { isPublicIp, ProxyCheckProvider, shouldBlockIpClassification } from "../src/index"; const ipAddress = "8.8.8.8"; function response(details: Record) { return new Response(JSON.stringify({ status: "ok", [ipAddress]: details }), { status: 200, headers: { "content-type": "application/json" }, }); } describe("ProxyCheck.io intelligence", () => { it("maps geolocation and a clear network response", async () => { const request = vi.fn().mockResolvedValue(response({ proxy: "no", type: "Business", risk: 2, city: "Mountain View", region: "California", country: "United States", isocode: "US", latitude: 37.4056, longitude: -122.0775, timezone: "America/Los_Angeles", asn: "AS15169", provider: "Google LLC", })); const result = await new ProxyCheckProvider({ apiKey: "secret", request }).classify(ipAddress); expect(result).toMatchObject({ classification: "clear", provider: "proxycheck", riskScore: 2, location: { city: "Mountain View", region: "California", country: "United States", countryCode: "US", latitude: 37.4056, longitude: -122.0775, timezone: "America/Los_Angeles", }, network: { asn: "AS15169", provider: "Google LLC", connectionType: "Business", proxy: false }, }); expect(request).toHaveBeenCalledWith( expect.stringContaining("https://proxycheck.io/v2/8.8.8.8"), expect.objectContaining({ signal: expect.any(AbortSignal) }), ); }); it("treats missing or malformed proxy signals as unknown", async () => { for (const proxy of [undefined, null, "maybe"] as const) { const request = vi.fn().mockResolvedValue(response({ proxy, type: "Residential" })); await expect(new ProxyCheckProvider({ apiKey: "secret", request }).classify(ipAddress)) .resolves.toMatchObject({ classification: "unknown", network: { proxy: null } }); } }); it("maps VPN and Tor responses to explicit classifications", async () => { const vpnRequest = vi.fn().mockResolvedValue(response({ proxy: "yes", type: "VPN" })); const torRequest = vi.fn().mockResolvedValue(response({ proxy: "yes", type: "TOR" })); await expect(new ProxyCheckProvider({ apiKey: "secret", request: vpnRequest }).classify(ipAddress)) .resolves.toMatchObject({ classification: "vpn" }); await expect(new ProxyCheckProvider({ apiKey: "secret", request: torRequest }).classify(ipAddress)) .resolves.toMatchObject({ classification: "tor" }); }); it("fails explicitly when ProxyCheck does not return usable data", async () => { const request = vi.fn().mockResolvedValue( new Response(JSON.stringify({ status: "denied", message: "Invalid API key" }), { status: 200 }), ); await expect(new ProxyCheckProvider({ apiKey: "secret", request }).classify(ipAddress)) .rejects.toThrow("ProxyCheck lookup failed"); }); }); describe("account-addition policy", () => { it("fails closed and blocks anonymizing networks", () => { expect(shouldBlockIpClassification("unknown", false)).toBe(true); expect(shouldBlockIpClassification("vpn", false)).toBe(true); expect(shouldBlockIpClassification("proxy", false)).toBe(true); expect(shouldBlockIpClassification("tor", false)).toBe(true); expect(shouldBlockIpClassification("clear", true)).toBe(false); expect(shouldBlockIpClassification("hosting", false)).toBe(false); expect(shouldBlockIpClassification("hosting", true)).toBe(true); }); }); describe("public IP filtering", () => { it("does not send private, loopback, documentation, or mapped-private addresses", () => { expect(isPublicIp("8.8.8.8")).toBe(true); expect(isPublicIp("10.0.0.1")).toBe(false); expect(isPublicIp("127.0.0.1")).toBe(false); expect(isPublicIp("203.0.113.10")).toBe(false); expect(isPublicIp("::ffff:192.168.1.1")).toBe(false); }); });