mirror of
https://github.com/google/nomulus.git
synced 2025-07-21 10:16:07 +02:00
Redact WHOIS output instead of removing the fields altogether
See https://www.icann.org/resources/pages/gtld-registration-data-specs-en/#appendixA for details on how certain fields are redacted. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=199295355
This commit is contained in:
parent
e1bcc2e64d
commit
643b30d31f
6 changed files with 236 additions and 70 deletions
|
@ -81,7 +81,7 @@ final class DomainWhoisResponse extends WhoisResponseImpl {
|
|||
.stream()
|
||||
.filter(RegistrarContact::getVisibleInDomainWhoisAsAbuse)
|
||||
.findFirst();
|
||||
DomainEmitter domainEmitter =
|
||||
return WhoisResponseResults.create(
|
||||
new DomainEmitter()
|
||||
.emitField(
|
||||
"Domain Name",
|
||||
|
@ -104,25 +104,22 @@ final class DomainWhoisResponse extends WhoisResponseImpl {
|
|||
"Registrar Abuse Contact Phone",
|
||||
abuseContact.map(RegistrarContact::getPhoneNumber).orElse(null))
|
||||
.emitStatusValues(domain.getStatusValues(), domain.getGracePeriods())
|
||||
.emitContact(
|
||||
"Registrant", Optional.of(domain.getRegistrant()), preferUnicode, fullOutput);
|
||||
if (fullOutput) {
|
||||
domainEmitter
|
||||
.emitContact("Admin", getContactReference(Type.ADMIN), preferUnicode, fullOutput)
|
||||
.emitContact("Tech", getContactReference(Type.TECH), preferUnicode, fullOutput)
|
||||
.emitContact("Billing", getContactReference(Type.BILLING), preferUnicode, fullOutput);
|
||||
}
|
||||
domainEmitter
|
||||
.emitSet(
|
||||
"Name Server",
|
||||
domain.loadNameserverFullyQualifiedHostNames(),
|
||||
hostName -> maybeFormatHostname(hostName, preferUnicode))
|
||||
.emitField("DNSSEC", isNullOrEmpty(domain.getDsData()) ? "unsigned" : "signedDelegation")
|
||||
.emitWicfLink()
|
||||
.emitLastUpdated(getTimestamp())
|
||||
.emitAwipMessage()
|
||||
.emitFooter(disclaimer);
|
||||
return WhoisResponseResults.create(domainEmitter.toString(), 1);
|
||||
.emitContact("Registrant", Optional.of(domain.getRegistrant()), preferUnicode)
|
||||
.emitContact("Admin", getContactReference(Type.ADMIN), preferUnicode)
|
||||
.emitContact("Tech", getContactReference(Type.TECH), preferUnicode)
|
||||
.emitContact("Billing", getContactReference(Type.BILLING), preferUnicode)
|
||||
.emitSet(
|
||||
"Name Server",
|
||||
domain.loadNameserverFullyQualifiedHostNames(),
|
||||
hostName -> maybeFormatHostname(hostName, preferUnicode))
|
||||
.emitField(
|
||||
"DNSSEC", isNullOrEmpty(domain.getDsData()) ? "unsigned" : "signedDelegation")
|
||||
.emitWicfLink()
|
||||
.emitLastUpdated(getTimestamp())
|
||||
.emitAwipMessage()
|
||||
.emitFooter(disclaimer)
|
||||
.toString(),
|
||||
1);
|
||||
}
|
||||
|
||||
/** Returns the contact of the given type. */
|
||||
|
@ -139,17 +136,15 @@ final class DomainWhoisResponse extends WhoisResponseImpl {
|
|||
if (phoneNumber == null) {
|
||||
return this;
|
||||
}
|
||||
return emitFieldIfDefined(ImmutableList.of(contactType, title), phoneNumber.getPhoneNumber())
|
||||
return emitFieldIfDefined(
|
||||
ImmutableList.of(contactType, title), phoneNumber.getPhoneNumber(), fullOutput)
|
||||
.emitFieldIfDefined(
|
||||
ImmutableList.of(contactType, title, "Ext"), phoneNumber.getExtension());
|
||||
ImmutableList.of(contactType, title, "Ext"), phoneNumber.getExtension(), fullOutput);
|
||||
}
|
||||
|
||||
/** Emit the contact entry of the given type. */
|
||||
DomainEmitter emitContact(
|
||||
String contactType,
|
||||
Optional<Key<ContactResource>> contact,
|
||||
boolean preferUnicode,
|
||||
boolean fullOutput) {
|
||||
String contactType, Optional<Key<ContactResource>> contact, boolean preferUnicode) {
|
||||
if (!contact.isPresent()) {
|
||||
return this;
|
||||
}
|
||||
|
@ -168,24 +163,21 @@ final class DomainWhoisResponse extends WhoisResponseImpl {
|
|||
preferUnicode,
|
||||
contactResource.getLocalizedPostalInfo(),
|
||||
contactResource.getInternationalizedPostalInfo());
|
||||
if (fullOutput) {
|
||||
// If the full output is to be displayed, show all fields for all contact types.
|
||||
// ICANN Consistent Labeling & Display policy requires that this be the ROID.
|
||||
emitField(ImmutableList.of("Registry", contactType, "ID"), contactResource.getRepoId());
|
||||
if (postalInfo != null) {
|
||||
emitFieldIfDefined(ImmutableList.of(contactType, "Name"), postalInfo.getName());
|
||||
emitFieldIfDefined(ImmutableList.of(contactType, "Organization"), postalInfo.getOrg());
|
||||
emitAddress(contactType, postalInfo.getAddress(), fullOutput);
|
||||
}
|
||||
emitPhone(contactType, "Phone", contactResource.getVoiceNumber());
|
||||
emitPhone(contactType, "Fax", contactResource.getFaxNumber());
|
||||
emitField(ImmutableList.of(contactType, "Email"), contactResource.getEmailAddress());
|
||||
} else {
|
||||
if (postalInfo != null) {
|
||||
emitFieldIfDefined(ImmutableList.of(contactType, "Organization"), postalInfo.getOrg());
|
||||
emitAddress(contactType, postalInfo.getAddress(), fullOutput);
|
||||
}
|
||||
// ICANN Consistent Labeling & Display policy requires that this be the ROID.
|
||||
emitField(
|
||||
ImmutableList.of("Registry", contactType, "ID"), contactResource.getRepoId(), fullOutput);
|
||||
if (postalInfo != null) {
|
||||
emitFieldIfDefined(ImmutableList.of(contactType, "Name"), postalInfo.getName(), fullOutput);
|
||||
emitFieldIfDefined(
|
||||
ImmutableList.of(contactType, "Organization"),
|
||||
postalInfo.getOrg(),
|
||||
fullOutput || contactType.equals("Registrant"));
|
||||
emitAddress(contactType, postalInfo.getAddress(), fullOutput);
|
||||
}
|
||||
emitPhone(contactType, "Phone", contactResource.getVoiceNumber());
|
||||
emitPhone(contactType, "Fax", contactResource.getFaxNumber());
|
||||
emitField(
|
||||
ImmutableList.of(contactType, "Email"), contactResource.getEmailAddress(), fullOutput);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,9 @@ abstract class WhoisResponseImpl implements WhoisResponse {
|
|||
/** ICANN problem reporting URL appended to all WHOIS responses. */
|
||||
private static final String ICANN_REPORTING_URL = "https://www.icann.org/wicf/";
|
||||
|
||||
/** Text to display when the field is redacted for privacy. */
|
||||
static final String REDACT_TEXT = "REDACTED FOR PRIVACY";
|
||||
|
||||
/** The time at which this response was created. */
|
||||
private final DateTime timestamp;
|
||||
|
||||
|
@ -94,59 +97,105 @@ abstract class WhoisResponseImpl implements WhoisResponse {
|
|||
return emitList(title, values.stream().map(transform).sorted().collect(toImmutableList()));
|
||||
}
|
||||
|
||||
/** Helper method that loops over a list of values and calls {@link #emitField}. */
|
||||
E emitList(String title, Iterable<String> values) {
|
||||
/**
|
||||
* Helper method that loops over a list of values and calls {@link #emitField}.
|
||||
*
|
||||
* <p>This method redacts the output unless {@code fullOutput} is {@code true}.
|
||||
*/
|
||||
E emitList(String title, Iterable<String> values, boolean fullOutput) {
|
||||
for (String value : values) {
|
||||
emitField(title, value);
|
||||
emitField(title, value, fullOutput);
|
||||
}
|
||||
return thisCastToDerived();
|
||||
}
|
||||
|
||||
/** Emit the field name and value followed by a newline, but only if a value exists. */
|
||||
E emitFieldIfDefined(String name, @Nullable String value) {
|
||||
/** Helper method that loops over a list of values and calls {@link #emitField}. */
|
||||
E emitList(String title, Iterable<String> values) {
|
||||
return emitList(title, values, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit the field name and value followed by a newline, but only if a value exists.
|
||||
*
|
||||
* <p>This method redacts the output unless {@code fullOutput} is {@code true}.
|
||||
*/
|
||||
E emitFieldIfDefined(String name, @Nullable String value, boolean fullOutput) {
|
||||
if (isNullOrEmpty(value)) {
|
||||
return thisCastToDerived();
|
||||
}
|
||||
stringBuilder.append(cleanse(name)).append(':');
|
||||
stringBuilder.append(' ').append(cleanse(value));
|
||||
stringBuilder.append(' ').append(fullOutput ? cleanse(value) : REDACT_TEXT);
|
||||
return emitNewline();
|
||||
}
|
||||
|
||||
/** Emit the field name and value followed by a newline, but only if a value exists. */
|
||||
E emitFieldIfDefined(String name, @Nullable String value) {
|
||||
return emitFieldIfDefined(name, value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a multi-part field name and value followed by a newline, but only if a value exists.
|
||||
*
|
||||
* <p>This method redacts the output unless {@code fullOutput} is {@code true}.
|
||||
*/
|
||||
E emitFieldIfDefined(List<String> nameParts, String value, boolean fullOutput) {
|
||||
if (isNullOrEmpty(value)) {
|
||||
return thisCastToDerived();
|
||||
}
|
||||
return emitField(nameParts, value, fullOutput);
|
||||
}
|
||||
|
||||
/** Emit a multi-part field name and value followed by a newline, but only if a value exists. */
|
||||
E emitFieldIfDefined(List<String> nameParts, String value) {
|
||||
return emitFieldIfDefined(nameParts, value, true);
|
||||
}
|
||||
/**
|
||||
* Emit the field name and value followed by a newline. /*
|
||||
*
|
||||
* <p>This method redacts the output unless {@code fullOutput} is {@code true}.
|
||||
*/
|
||||
E emitField(String name, @Nullable String value, boolean fullOutput) {
|
||||
stringBuilder.append(cleanse(name)).append(':');
|
||||
if (!isNullOrEmpty(value)) {
|
||||
stringBuilder.append(' ').append(fullOutput ? cleanse(value) : REDACT_TEXT);
|
||||
}
|
||||
return emitNewline();
|
||||
}
|
||||
|
||||
/** Emit the field name and value followed by a newline. */
|
||||
E emitField(String name, @Nullable String value) {
|
||||
stringBuilder.append(cleanse(name)).append(':');
|
||||
if (!isNullOrEmpty(value)) {
|
||||
stringBuilder.append(' ').append(cleanse(value));
|
||||
}
|
||||
return emitNewline();
|
||||
return emitField(name, value, true);
|
||||
}
|
||||
|
||||
/** Emit a multi-part field name and value followed by a newline, but only if a value exists. */
|
||||
E emitFieldIfDefined(List<String> nameParts, String value) {
|
||||
if (isNullOrEmpty(value)) {
|
||||
return thisCastToDerived();
|
||||
}
|
||||
return emitField(nameParts, value);
|
||||
/**
|
||||
* Emit a multi-part field name and value followed by a newline.
|
||||
*
|
||||
* <p>This method redacts the output unless {@code fullOutput} is {@code true}.
|
||||
*/
|
||||
E emitField(List<String> nameParts, String value, boolean fullOutput) {
|
||||
return emitField(Joiner.on(' ').join(nameParts), value, fullOutput);
|
||||
}
|
||||
|
||||
/** Emit a multi-part field name and value followed by a newline. */
|
||||
E emitField(List<String> nameParts, String value) {
|
||||
return emitField(Joiner.on(' ').join(nameParts), value);
|
||||
return emitField(nameParts, value, true);
|
||||
}
|
||||
|
||||
/** Emit a contact address. */
|
||||
E emitAddress(@Nullable String prefix, @Nullable Address address, boolean fullOutput) {
|
||||
prefix = isNullOrEmpty(prefix) ? "" : prefix + " ";
|
||||
if (address != null) {
|
||||
if (fullOutput) {
|
||||
emitList(prefix + "Street", address.getStreet());
|
||||
emitField(prefix + "City", address.getCity());
|
||||
}
|
||||
emitField(prefix + "State/Province", address.getState());
|
||||
if (fullOutput) {
|
||||
emitField(prefix + "Postal Code", address.getZip());
|
||||
}
|
||||
emitField(prefix + "Country", address.getCountryCode());
|
||||
emitList(prefix + "Street", address.getStreet(), fullOutput);
|
||||
emitField(prefix + "City", address.getCity(), fullOutput);
|
||||
emitField(
|
||||
prefix + "State/Province",
|
||||
address.getState(),
|
||||
(fullOutput || prefix.equals("Registrant ")));
|
||||
emitField(prefix + "Postal Code", address.getZip(), fullOutput);
|
||||
emitField(
|
||||
prefix + "Country",
|
||||
address.getCountryCode(),
|
||||
fullOutput || prefix.equals("Registrant "));
|
||||
}
|
||||
return thisCastToDerived();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue