mirror of
https://github.com/jakejarvis/rdapper.git
synced 2026-09-23 00:15:31 -04:00
fix: tighten isPrivacyName to avoid false positives on ambiguous privacy words
- Split keyword list into `PRIVACY_STRONG_KEYWORDS` (matched as plain substrings) and two weaker sets (`PRIVACY_WEAK_WORDS` / `PRIVACY_CONTEXT_WORDS`) that only trigger when at least two distinct terms appear together, preventing names like "Private Equity Partners LLC" or "Protection One" from being misclassified - Remove empty-placeholder values (`-`, `n/a`, `none`, etc.) from the privacy check; they are not privacy notices and should be handled separately by callers - Add `privacy.test.ts` covering redaction notices, known privacy-service names, ordinary names with ambiguous words, and empty placeholders - Update README comment to clarify that `privacyEnabled` is set by name heuristics (privacy-service and redaction phrases) or RFC 9537 redactions
This commit is contained in:
@@ -555,7 +555,7 @@ interface DomainRecord {
|
|||||||
country?: string;
|
country?: string;
|
||||||
countryCode?: string;
|
countryCode?: string;
|
||||||
}>;
|
}>;
|
||||||
privacyEnabled?: boolean; // registrant appears privacy-redacted based on keyword heuristics or RFC 9537 redactions
|
privacyEnabled?: boolean; // registrant appears privacy-redacted based on name heuristics (privacy-service and redaction phrases) or RFC 9537 redactions
|
||||||
redactions?: Array<{
|
redactions?: Array<{
|
||||||
name: string; // e.g. "Registrant Email"
|
name: string; // e.g. "Registrant Email"
|
||||||
prePath?: string;
|
prePath?: string;
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { expect, test } from "vitest";
|
||||||
|
import { isPrivacyName } from "./privacy";
|
||||||
|
|
||||||
|
test("isPrivacyName flags redaction notices and privacy services", () => {
|
||||||
|
for (const v of [
|
||||||
|
"REDACTED FOR PRIVACY",
|
||||||
|
"Data Redacted",
|
||||||
|
"Privacy Protect, LLC",
|
||||||
|
"WhoisGuard Protected",
|
||||||
|
"Domains By Proxy, LLC",
|
||||||
|
"Private Registration",
|
||||||
|
"Domain Protection Services",
|
||||||
|
"Identity Protection Service",
|
||||||
|
"Withheld for Privacy ehf",
|
||||||
|
"Datos Privados",
|
||||||
|
]) {
|
||||||
|
expect(isPrivacyName(v), v).toBe(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("isPrivacyName does not flag ordinary names with ambiguous words", () => {
|
||||||
|
for (const v of ["Private Equity Partners LLC", "Protection One", "Jane Private", "Acme Inc"]) {
|
||||||
|
expect(isPrivacyName(v), v).toBe(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("isPrivacyName does not treat empty placeholders as privacy", () => {
|
||||||
|
for (const v of ["-", "n/a", "N/A", "none", "not available"]) {
|
||||||
|
expect(isPrivacyName(v), v).toBe(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
+43
-23
@@ -1,41 +1,61 @@
|
|||||||
export const PRIVACY_NAME_KEYWORDS = [
|
/**
|
||||||
"redacted",
|
* Phrases that indicate privacy/redaction on their own. Matched as case-insensitive substrings.
|
||||||
"privacy",
|
*/
|
||||||
"private",
|
export const PRIVACY_STRONG_KEYWORDS = [
|
||||||
|
"redacted", // also covers "redacted for privacy", "redacted.forprivacy"
|
||||||
"withheld",
|
"withheld",
|
||||||
"not disclosed",
|
"not disclosed",
|
||||||
"protected",
|
|
||||||
"protection",
|
|
||||||
"privado", // Spanish
|
"privado", // Spanish
|
||||||
"datos privados", // Spanish
|
"datos privados", // Spanish
|
||||||
"data protected",
|
"data protected",
|
||||||
"data redacted",
|
|
||||||
"gdpr redacted",
|
|
||||||
"gdpr masked",
|
"gdpr masked",
|
||||||
"non-public data",
|
"non-public data",
|
||||||
"statutory masking",
|
"statutory masking",
|
||||||
"redacted.forprivacy",
|
|
||||||
"registration private",
|
"registration private",
|
||||||
|
"private registration",
|
||||||
"hidden upon user request",
|
"hidden upon user request",
|
||||||
"not available from registry",
|
"not available from registry",
|
||||||
|
"whois privacy",
|
||||||
|
"whoisguard",
|
||||||
|
"privacy protect",
|
||||||
|
"privacy service",
|
||||||
|
"domain privacy",
|
||||||
|
"contact privacy",
|
||||||
|
"domains by proxy",
|
||||||
|
"proxy service",
|
||||||
|
"for privacy",
|
||||||
];
|
];
|
||||||
|
|
||||||
// Completely unusable/empty values that should be filtered
|
/**
|
||||||
export const NO_DATA_VALUES = [
|
* Words too ambiguous to trust alone ("Private Equity LLC", "Protection One"). They only count
|
||||||
"-",
|
* when at least two distinct terms from WEAK + CONTEXT appear as whole words.
|
||||||
".",
|
*/
|
||||||
"n/a",
|
const PRIVACY_WEAK_WORDS = ["privacy", "private", "protect", "protected", "protection"];
|
||||||
"na",
|
const PRIVACY_CONTEXT_WORDS = [
|
||||||
"no data",
|
"whois",
|
||||||
"not available",
|
"proxy",
|
||||||
"not applicable",
|
"domain",
|
||||||
"none",
|
"domains",
|
||||||
|
"registration",
|
||||||
|
"guard",
|
||||||
|
"service",
|
||||||
|
"services",
|
||||||
|
"masked",
|
||||||
|
"anonymous",
|
||||||
|
"identity",
|
||||||
|
"contact",
|
||||||
];
|
];
|
||||||
|
const WEAK_WORD_RE = new RegExp(`\\b(?:${PRIVACY_WEAK_WORDS.join("|")})\\b`, "g");
|
||||||
|
const CONTEXT_WORD_RE = new RegExp(
|
||||||
|
`\\b(?:${[...PRIVACY_WEAK_WORDS, ...PRIVACY_CONTEXT_WORDS].join("|")})\\b`,
|
||||||
|
"g",
|
||||||
|
);
|
||||||
|
|
||||||
|
/** True when a registrant name/organization looks like a privacy service or redaction notice. */
|
||||||
export function isPrivacyName(value: string): boolean {
|
export function isPrivacyName(value: string): boolean {
|
||||||
const v = value.toLowerCase().trim();
|
const v = value.toLowerCase().trim();
|
||||||
// Check for complete no-data values
|
if (PRIVACY_STRONG_KEYWORDS.some((k) => v.includes(k))) return true;
|
||||||
if (NO_DATA_VALUES.includes(v)) return true;
|
if (!WEAK_WORD_RE.test(v)) return false;
|
||||||
// Check for privacy keywords
|
WEAK_WORD_RE.lastIndex = 0;
|
||||||
return PRIVACY_NAME_KEYWORDS.some((k) => v.includes(k));
|
return new Set(v.match(CONTEXT_WORD_RE)).size >= 2;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user