diff --git a/lib/index.mjs b/lib/index.mjs index d276e77..6c21560 100644 --- a/lib/index.mjs +++ b/lib/index.mjs @@ -119,6 +119,11 @@ export function parseRegistryName(hostname) { // registry rejects sends a tab to a page saying it does not exist. const LABEL = /^[a-z0-9]{1,63}$/; if (!LABEL.test(label) || !LABEL.test(tld)) return null; + // Both halves numeric is refused by the registry — several parsers read a + // two-part dotted number as an abbreviated IPv4 literal, so `1.420` is + // genuinely ambiguous where `blue.420` is not. Accepting it here would send + // a tab to a parking page for a name the registry can never register. + if (/^\d+$/.test(label) && /^\d+$/.test(tld)) return null; return { label, tld }; } diff --git a/test/resolve.test.mjs b/test/resolve.test.mjs index 2afade7..83c906e 100644 --- a/test/resolve.test.mjs +++ b/test/resolve.test.mjs @@ -241,4 +241,9 @@ test("dashes are not part of a Moshpit name", () => { } assert.deepEqual(parseRegistryName("california.oranges"), { label: "california", tld: "oranges" }); assert.deepEqual(parseRegistryName("blue.420"), { label: "blue", tld: "420" }); + // Both halves numeric is refused by the registry (reads as an abbreviated + // IPv4 literal), so the port refuses it too — otherwise a tab lands on a + // parking page for a name the registry can never register. + assert.equal(parseRegistryName("1.420"), null, "1.420"); + assert.equal(parseRegistryName("420.187"), null, "420.187"); });