From 87b85f7d3d0f96ee0cf3683336f5d667b4bbcb5d Mon Sep 17 00:00:00 2001 From: Jake Jarvis Date: Wed, 22 Oct 2025 17:45:19 -0400 Subject: [PATCH] Add query transformation for non-English WHOIS servers, specifically for whois.jprs.jp (fixes #15) --- src/whois/client.test.ts | 37 +++++++++++++++++++++++++++++++++++++ src/whois/client.ts | 18 +++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/whois/client.test.ts b/src/whois/client.test.ts index 2c5b829..4fc3c1f 100644 --- a/src/whois/client.test.ts +++ b/src/whois/client.test.ts @@ -13,3 +13,40 @@ describe("edge runtime behavior", () => { ); }); }); + +describe("query transformation for non-English WHOIS servers", () => { + it("should append /e to queries for whois.jprs.jp", async () => { + // Mock net module to capture the query being sent + let capturedQuery = ""; + + vi.doMock("node:net", () => ({ + createConnection: () => { + return { + on: (event: string, callback: (arg?: unknown) => void) => { + if (event === "connect") { + // Capture the query that will be written + setTimeout(() => callback(), 0); + } else if (event === "end") { + setTimeout(() => callback(), 10); + } + }, + write: (data: string) => { + capturedQuery = data.replace(/\r\n$/, ""); // Strip CRLF + }, + destroy: () => {}, + setTimeout: () => {}, + }; + }, + })); + + const { whoisQuery } = await import("../whois/client"); + + try { + await whoisQuery("whois.jprs.jp", "hairtect.jp"); + } catch { + // Query may fail since we're mocking, but we just want to check the query format + } + + expect(capturedQuery).toBe("hairtect.jp/e"); + }); +}); diff --git a/src/whois/client.ts b/src/whois/client.ts index 40ceca4..e8d3826 100644 --- a/src/whois/client.ts +++ b/src/whois/client.ts @@ -7,6 +7,17 @@ export interface WhoisQueryResult { text: string; } +/** + * Some WHOIS servers default to non-English responses. This mapping allows automatic + * query transformation to request English-only output for easier parsing. + * + * To add new servers: Add an entry with the hostname and transformation function: + * "whois.example.org": (query) => `${query}/english`, + */ +const WHOIS_QUERY_TRANSFORMERS: Record string> = { + "whois.jprs.jp": (query) => `${query}/e`, // Append /e for English-only response +}; + /** * Perform a WHOIS query against an RFC 3912 server over TCP 43. * Returns the raw text and the server used. @@ -19,8 +30,13 @@ export async function whoisQuery( const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS; const port = 43; const host = server.replace(/^whois:\/\//i, ""); + + // Transform query if server requires special formatting + const transformer = WHOIS_QUERY_TRANSFORMERS[host]; + const transformedQuery = transformer ? transformer(query) : query; + const text = await withTimeout( - queryTcp(host, port, query, options), + queryTcp(host, port, transformedQuery, options), timeoutMs, "WHOIS timeout", );