1
mirror of https://github.com/jakejarvis/rdapper.git synced 2025-10-18 20:14:27 -04:00

Enhance date parsing in WHOIS and add tests for registrar expiration dates

Updated the `toISO` function to handle various timezone formats in WHOIS date strings. Added tests to verify parsing of registrar registration expiration dates and EDUCAUSE format dates in the normalization process. This improves the accuracy of date handling in WHOIS responses.
This commit is contained in:
2025-10-08 19:39:56 -04:00
parent f8280508ff
commit 9661db0b46
4 changed files with 83 additions and 12 deletions

View File

@@ -18,4 +18,11 @@ test("toISO parses ISO and common whois formats", () => {
const mdy = toISO("Jan 02 2023");
expect(mdy).toBe("2023-01-02T00:00:00Z");
// Registrar style timezone offsets
const plus0000 = toISO("2025-03-23T10:53:03+0000");
expect(plus0000).toBe("2025-03-23T10:53:03Z");
const plus0000Space = toISO("2025-03-23 10:53:03+0000");
expect(plus0000Space).toBe("2025-03-23T10:53:03Z");
const plus0530 = toISO("2025-03-23T10:53:03+05:30");
expect(plus0530).toBe("2025-03-23T05:23:03Z");
});

View File

@@ -11,9 +11,9 @@ export function toISO(
// Try several structured formats seen in WHOIS outputs (treat as UTC when no TZ provided)
const tryFormats = [
// 2023-01-02 03:04:05Z or without Z
/^(\d{4})-(\d{2})-(\d{2})[ T](\d{2}):(\d{2}):(\d{2})(?:Z)?$/,
/^(\d{4})-(\d{2})-(\d{2})[ T](\d{2}):(\d{2}):(\d{2})(?:Z|([+-]\d{2})(?::?(\d{2}))?)?$/,
// 2023/01/02 03:04:05
/^(\d{4})\/(\d{2})\/(\d{2})[ T](\d{2}):(\d{2}):(\d{2})$/,
/^(\d{4})\/(\d{2})\/(\d{2})[ T](\d{2}):(\d{2}):(\d{2})(?:Z|([+-]\d{2})(?::?(\d{2}))?)?$/,
// 02-Jan-2023
/^(\d{2})-([A-Za-z]{3})-(\d{4})$/,
// Jan 02 2023
@@ -69,17 +69,26 @@ function parseWithRegex(m: RegExpMatchArray, _re: RegExp): Date | undefined {
try {
// If the matched string contains time components, parse as Y-M-D H:M:S
if (m[0].includes(":")) {
const [_, y, mo, d, hh, mm, ss] = m;
return new Date(
Date.UTC(
Number(y),
Number(mo) - 1,
Number(d),
Number(hh),
Number(mm),
Number(ss),
),
const [_, y, mo, d, hh, mm, ss, offH, offM] = m;
// Base time as UTC
let dt = Date.UTC(
Number(y),
Number(mo) - 1,
Number(d),
Number(hh),
Number(mm),
Number(ss),
);
// Apply timezone offset if present (e.g., +0000, -0500, +05:30)
if (offH) {
const sign = offH.startsWith("-") ? -1 : 1;
const hours = Math.abs(Number(offH));
const minutes = offM ? Number(offM) : 0;
const offsetMs = sign * (hours * 60 + minutes) * 60 * 1000;
// The captured time is local with an explicit offset; convert to UTC
dt -= offsetMs;
}
return new Date(dt);
}
// If the matched string contains hyphens, treat as DD-MMM-YYYY
if (m[0].includes("-")) {

View File

@@ -96,6 +96,49 @@ DNSSEC: unsigned
expect(rec.nameservers && rec.nameservers.length === 2).toBe(true);
});
test("WHOIS registrar response with Registrar Registration Expiration Date", () => {
const text = `
Domain Name: EXAMPLE.US
Registrar WHOIS Server: whois.registrar.test
Registrar URL: http://www.registrar.test
Updated Date: 2025-03-23T10:53:03+0000
Creation Date: 2020-04-24T15:03:39+0000
Registrar Registration Expiration Date: 2027-04-23T00:00:00+0000
Registrar: Registrar LLC
`;
const rec = normalizeWhois(
"example.us",
"us",
text,
"whois.registrar.test",
"2025-01-01T00:00:00Z",
);
expect(Boolean(rec.expirationDate)).toBe(true);
expect(rec.expirationDate).toBe("2027-04-23T00:00:00Z");
});
test("WHOIS .edu EDUCAUSE format", () => {
const text = `
This Registry database contains ONLY .EDU domains.
Domain Name: TUFTS.EDU
Domain record activated: 22-Jun-1987
Domain record last updated: 02-Jul-2025
Domain expires: 31-Jul-2026
`;
const rec = normalizeWhois(
"tufts.edu",
"edu",
text,
"whois.educause.edu",
"2025-01-01T00:00:00Z",
);
expect(rec.creationDate).toBe("1987-06-22T00:00:00Z");
expect(rec.updatedDate).toBe("2025-07-02T00:00:00Z");
expect(rec.expirationDate).toBe("2026-07-31T00:00:00Z");
});
test("Privacy redacted WHOIS normalizes without contacts", () => {
const text = `
Domain Name: EXAMPLE.COM

View File

@@ -31,17 +31,29 @@ export function normalizeWhois(
"domain create date",
"created",
"registered",
// EDUCAUSE (.edu)
"domain record activated",
]);
const updatedDate = anyValue(map, [
"updated date",
"last updated",
"last modified",
"modified",
// EDUCAUSE (.edu)
"domain record last updated",
]);
const expirationDate = anyValue(map, [
"registry expiry date",
"registry expiration date",
"expiry date",
"expiration date",
// Registrar-side synonyms commonly seen after referrals
"registrar registration expiration date",
"registrar registration expiry date",
"registrar expiration date",
"registrar expiry date",
// EDUCAUSE (.edu)
"domain expires",
"paid-till",
"expires on",
"renewal date",