1
mirror of https://github.com/jakejarvis/rdapper.git synced 2026-01-27 21:45:19 -05:00

fix: improve transfer lock status detection

This commit is contained in:
2025-12-30 12:43:55 -05:00
parent 1b73b7dc8d
commit ab1326d99c
4 changed files with 62 additions and 4 deletions

View File

@@ -100,3 +100,21 @@ test("normalizeRdap derives privacyEnabled from registrant keywords", () => {
]);
expect(rec.privacyEnabled).toBe(true);
});
test("normalizeRdap detects transfer lock with spaced status", () => {
const rdap = {
ldhName: "example.com",
status: ["client transfer prohibited"],
};
const rec = normalizeRdap("example.com", "com", rdap, []);
expect(rec.transferLock).toBe(true);
});
test("normalizeRdap detects transfer lock with camelCase status", () => {
const rdap = {
ldhName: "example.com",
status: ["clientTransferProhibited"],
};
const rec = normalizeRdap("example.com", "com", rdap, []);
expect(rec.transferLock).toBe(true);
});

View File

@@ -121,7 +121,7 @@ export function normalizeRdap(
// Derive a simple transfer lock flag from statuses
const transferLock = !!statuses?.some((s: { status: string }) =>
/transferprohibited/i.test(s.status),
/transfer[-\s]*prohibited/i.test(s.status),
);
// The RDAP document may include "port43" pointer to authoritative WHOIS

View File

@@ -1,5 +1,5 @@
import { expect, test } from "vitest";
import { normalizeWhois } from "./normalize";
import { isAvailableByWhois, normalizeWhois } from "./normalize";
test("WHOIS .de (DENIC-like) nserver lines", () => {
const text = `
@@ -186,3 +186,34 @@ Registrant Organization: Example Org
);
expect(rec.privacyEnabled).toBe(true);
});
test("isAvailableByWhois correctly identifies availability patterns", () => {
const patterns = [
"Domain not found",
"No information available",
"no se encuentra registrado",
"object_not_found",
"is free",
"no data was found",
"no entries found",
"No Data Found",
"No information was found",
"No match",
"No object found",
"Not been registered",
"Does not exist",
"NOT FOUND",
"Status: free",
"Status: available",
"unassignable",
];
for (const pattern of patterns) {
expect(isAvailableByWhois(pattern)).toBe(true);
}
// Also verify that normalizeWhois marks isRegistered=false
const text = "Domain not found";
const rec = normalizeWhois("example.com", "com", text, "whois.example.com");
expect(rec.isRegistered).toBe(false);
});

View File

@@ -14,17 +14,26 @@ const WHOIS_AVAILABLE_PATTERNS: RegExp[] = [
/\bnot found\b/i,
/\bno entries found\b/i,
/\bno data found\b/i,
/\bno information available\b/i,
/\bno information was found\b/i,
/\bno data was found\b/i,
/\bavailable for registration\b/i,
/\bdomain\s+available\b/i,
/\bdomain status[:\s]+available\b/i,
/\bobject does not exist\b/i,
/\bthe queried object does not exist\b/i,
/\bqueried object does not exist\b/i,
/\bdoes not exist\b/i,
/\breturned 0 objects\b/i,
/\bnot been registered\b/i,
/\bunassignable\b/i,
/\bis free\b/i,
// Common variants across ccTLDs/registrars
/\bstatus:\s*free\b/i,
/\bstatus:\s*available\b/i,
/\bno object found\b/i,
/\bobject_not_found\b/i,
/\bno se encuentra registrado\b/i, // Spanish: "not found registered"
/\bnicht gefunden\b/i, // German: "not found"
/\bpending release\b/i, // often signals not registered/being deleted
];
@@ -224,8 +233,8 @@ export function normalizeWhois(
: undefined;
// Simple lock derivation from statuses
const transferLock = !!statuses?.some(
(s) => s.status && /transferprohibited/i.test(s.status),
const transferLock = !!statuses?.some((s) =>
/transfer[-\s]*prohibited/i.test(s.raw || s.status || ""),
);
const record: DomainRecord = {