// Tests for server/anon-trial.js — focused on getClientIp, which underpins // the per-IP trial cap. The DB-backed minting paths need a multi-mode SQLite // handle and are exercised by integration tests; here we lock down that the // client IP is taken from Express's trust-proxy-resolved req.ip, never from a // raw client-supplied X-Forwarded-For header. import { test, describe } from "node:test"; import { strict as assert } from "node:assert"; import { getClientIp } from "../anon-trial.js"; describe("getClientIp", () => { test("uses req.ip (Express's trust-proxy-resolved client address)", () => { assert.equal(getClientIp({ ip: "203.0.113.7" }), "203.0.113.7"); }); test("strips the IPv4-mapped IPv6 prefix", () => { assert.equal(getClientIp({ ip: "::ffff:203.0.113.7" }), "203.0.113.7"); }); test("falls back to the socket address when req.ip is absent", () => { assert.equal( getClientIp({ socket: { remoteAddress: "::ffff:198.51.100.9" } }), "198.51.100.9", ); }); test("does NOT trust a raw client-supplied X-Forwarded-For header", () => { // Express, not getClientIp, decides the client IP from trust proxy. A // header Express hasn't blessed must be ignored — so with no req.ip we // fall through to the socket address, never the spoofed header value. const spoofed = { headers: { "x-forwarded-for": "1.2.3.4" }, socket: { remoteAddress: "203.0.113.7" }, }; assert.equal(getClientIp(spoofed), "203.0.113.7"); }); });