mirror of
https://github.com/google/nomulus
synced 2026-01-05 04:56:03 +00:00
Make all contacts nullable in the data model (#2490)
This doesn't yet allow them to be absent in EPP flows, but it should make the code not break if they happen to be null in the database. This is a follow-up to PR #2477, which ends up being a bit easier because whereas the registrant is used in more parts of the codebase, the other contact types (admin, technical, billing) are really only used in RDE, WHOIS, and RDAP, and because they were already being used as a collection anyway, the handling for if that collection contains fewer elements or is empty happened to already be mostly correct.
This commit is contained in:
@@ -466,13 +466,10 @@ public class RdePipeline implements Serializable {
|
||||
// Contacts and hosts are only deposited in RDE, not BRDA.
|
||||
if (pendingDeposit.mode() == RdeMode.FULL) {
|
||||
HashSet<Serializable> contacts = new HashSet<>();
|
||||
contacts.add(domain.getAdminContact().getKey());
|
||||
contacts.add(domain.getTechContact().getKey());
|
||||
domain.getRegistrant().ifPresent(r -> contacts.add(r.getKey()));
|
||||
// Billing contact is not mandatory.
|
||||
if (domain.getBillingContact() != null) {
|
||||
contacts.add(domain.getBillingContact().getKey());
|
||||
}
|
||||
domain.getAdminContact().ifPresent(c -> contacts.add(c.getKey()));
|
||||
domain.getTechContact().ifPresent(c -> contacts.add(c.getKey()));
|
||||
domain.getRegistrant().ifPresent(c -> contacts.add(c.getKey()));
|
||||
domain.getBillingContact().ifPresent(c -> contacts.add(c.getKey()));
|
||||
referencedContactCounter.inc(contacts.size());
|
||||
contacts.forEach(
|
||||
contactRepoId ->
|
||||
|
||||
@@ -46,6 +46,7 @@ import google.registry.model.EppResource;
|
||||
import google.registry.model.EppResource.ResourceWithTransferData;
|
||||
import google.registry.model.billing.BillingRecurrence;
|
||||
import google.registry.model.contact.Contact;
|
||||
import google.registry.model.domain.DesignatedContact.Type;
|
||||
import google.registry.model.domain.launch.LaunchNotice;
|
||||
import google.registry.model.domain.rgp.GracePeriodStatus;
|
||||
import google.registry.model.domain.secdns.DomainDsData;
|
||||
@@ -131,10 +132,10 @@ public class DomainBase extends EppResource
|
||||
@Expose @Transient Set<VKey<Host>> nsHosts;
|
||||
|
||||
/** Contacts. */
|
||||
@Expose VKey<Contact> adminContact;
|
||||
@Expose @Nullable VKey<Contact> adminContact;
|
||||
|
||||
@Expose VKey<Contact> billingContact;
|
||||
@Expose VKey<Contact> techContact;
|
||||
@Expose @Nullable VKey<Contact> billingContact;
|
||||
@Expose @Nullable VKey<Contact> techContact;
|
||||
@Expose @Nullable VKey<Contact> registrantContact;
|
||||
|
||||
/** Authorization info (aka transfer secret) of the domain. */
|
||||
@@ -589,24 +590,32 @@ public class DomainBase extends EppResource
|
||||
return Optional.ofNullable(registrantContact);
|
||||
}
|
||||
|
||||
public VKey<Contact> getAdminContact() {
|
||||
return adminContact;
|
||||
public Optional<VKey<Contact>> getAdminContact() {
|
||||
return Optional.ofNullable(adminContact);
|
||||
}
|
||||
|
||||
public VKey<Contact> getBillingContact() {
|
||||
return billingContact;
|
||||
public Optional<VKey<Contact>> getBillingContact() {
|
||||
return Optional.ofNullable(billingContact);
|
||||
}
|
||||
|
||||
public VKey<Contact> getTechContact() {
|
||||
return techContact;
|
||||
public Optional<VKey<Contact>> getTechContact() {
|
||||
return Optional.ofNullable(techContact);
|
||||
}
|
||||
|
||||
/** Associated contacts for the domain (other than registrant). */
|
||||
/**
|
||||
* Associated contacts for the domain (other than registrant).
|
||||
*
|
||||
* <p>Note: This can be an empty set if no contacts are present for the domain.
|
||||
*/
|
||||
public ImmutableSet<DesignatedContact> getContacts() {
|
||||
return getAllContacts(false);
|
||||
}
|
||||
|
||||
/** Gets all associated contacts for the domain, including the registrant. */
|
||||
/**
|
||||
* Gets all associated contacts for the domain, including the registrant.
|
||||
*
|
||||
* <p>Note: This can be an empty set if no contacts are present for the domain.
|
||||
*/
|
||||
public ImmutableSet<DesignatedContact> getAllContacts() {
|
||||
return getAllContacts(true);
|
||||
}
|
||||
@@ -615,7 +624,11 @@ public class DomainBase extends EppResource
|
||||
return authInfo;
|
||||
}
|
||||
|
||||
/** Returns all referenced contacts from this domain. */
|
||||
/**
|
||||
* Returns all referenced contacts from this domain.
|
||||
*
|
||||
* <p>Note: This can be an empty set if no contacts are present for the domain.
|
||||
*/
|
||||
public ImmutableSet<VKey<Contact>> getReferencedContacts() {
|
||||
return nullToEmptyImmutableCopy(getAllContacts(true)).stream()
|
||||
.map(DesignatedContact::getContactKey)
|
||||
@@ -625,18 +638,12 @@ public class DomainBase extends EppResource
|
||||
|
||||
private ImmutableSet<DesignatedContact> getAllContacts(boolean includeRegistrant) {
|
||||
ImmutableSet.Builder<DesignatedContact> builder = new ImmutableSet.Builder<>();
|
||||
if (includeRegistrant && registrantContact != null) {
|
||||
builder.add(DesignatedContact.create(DesignatedContact.Type.REGISTRANT, registrantContact));
|
||||
}
|
||||
if (adminContact != null) {
|
||||
builder.add(DesignatedContact.create(DesignatedContact.Type.ADMIN, adminContact));
|
||||
}
|
||||
if (billingContact != null) {
|
||||
builder.add(DesignatedContact.create(DesignatedContact.Type.BILLING, billingContact));
|
||||
}
|
||||
if (techContact != null) {
|
||||
builder.add(DesignatedContact.create(DesignatedContact.Type.TECH, techContact));
|
||||
if (includeRegistrant) {
|
||||
getRegistrant().ifPresent(c -> builder.add(DesignatedContact.create(Type.REGISTRANT, c)));
|
||||
}
|
||||
getAdminContact().ifPresent(c -> builder.add(DesignatedContact.create(Type.ADMIN, c)));
|
||||
getBillingContact().ifPresent(c -> builder.add(DesignatedContact.create(Type.BILLING, c)));
|
||||
getTechContact().ifPresent(c -> builder.add(DesignatedContact.create(Type.TECH, c)));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@@ -652,11 +659,13 @@ public class DomainBase extends EppResource
|
||||
*/
|
||||
void setContactFields(Set<DesignatedContact> contacts, boolean includeRegistrant) {
|
||||
// Set the individual contact fields.
|
||||
billingContact = techContact = adminContact = null;
|
||||
billingContact = null;
|
||||
techContact = null;
|
||||
adminContact = null;
|
||||
if (includeRegistrant) {
|
||||
registrantContact = null;
|
||||
}
|
||||
HashSet<DesignatedContact.Type> contactsDiscovered = new HashSet<>();
|
||||
HashSet<Type> contactsDiscovered = new HashSet<>();
|
||||
for (DesignatedContact contact : contacts) {
|
||||
checkArgument(
|
||||
!contactsDiscovered.contains(contact.getType()),
|
||||
@@ -687,7 +696,7 @@ public class DomainBase extends EppResource
|
||||
|
||||
/** Predicate to determine if a given {@link DesignatedContact} is the registrant. */
|
||||
static final Predicate<DesignatedContact> IS_REGISTRANT =
|
||||
(DesignatedContact contact) -> DesignatedContact.Type.REGISTRANT.equals(contact.type);
|
||||
(DesignatedContact contact) -> Type.REGISTRANT.equals(contact.type);
|
||||
|
||||
/** An override of {@link EppResource#asBuilder} with tighter typing. */
|
||||
@Override
|
||||
|
||||
@@ -381,8 +381,11 @@ public class RdapJsonFormatter {
|
||||
() ->
|
||||
ImmutableSet.copyOf(replicaTm().loadByKeys(domain.getNameservers()).values()));
|
||||
// Load the registrant and other contacts and add them to the data.
|
||||
ImmutableSet<VKey<Contact>> contacts = domain.getReferencedContacts();
|
||||
ImmutableMap<VKey<? extends Contact>, Contact> loadedContacts =
|
||||
replicaTm().transact(() -> replicaTm().loadByKeysIfPresent(domain.getReferencedContacts()));
|
||||
contacts.isEmpty()
|
||||
? ImmutableMap.of()
|
||||
: replicaTm().transact(() -> replicaTm().loadByKeysIfPresent(contacts));
|
||||
|
||||
// RDAP Response Profile 2.7.1, 2.7.3 - we MUST have the contacts. 2.7.4 discusses redaction of
|
||||
// fields we don't want to show (as opposed to not having contacts at all) because of GDPR etc.
|
||||
@@ -544,7 +547,8 @@ public class RdapJsonFormatter {
|
||||
// TODO(mcilwain): Once the RDAP profile is fully updated for minimum registration data set,
|
||||
// we will want to not include non-existent contacts at all, rather than
|
||||
// pretending they exist and just showing REDACTED info. This is especially
|
||||
// important for authorized flows, where you wouldn't expect to see redaction.
|
||||
// important for authorized flows, where you wouldn't expect to see redaction
|
||||
// (although no one actually has access to authorized flows yet).
|
||||
boolean isAuthorized =
|
||||
contact.isPresent()
|
||||
&& rdapAuthorization.isAuthorizedForRegistrar(
|
||||
|
||||
@@ -235,6 +235,19 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, Domain> {
|
||||
doSuccessfulTest("domain_info_response_no_registrant.xml", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_noContacts() throws Exception {
|
||||
persistTestEntities(false);
|
||||
domain =
|
||||
persistResource(
|
||||
domain
|
||||
.asBuilder()
|
||||
.setRegistrant(Optional.empty())
|
||||
.setContacts(ImmutableSet.of())
|
||||
.build());
|
||||
doSuccessfulTest("domain_info_response_no_contacts.xml", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_clTridNotSpecified() throws Exception {
|
||||
setEppInput("domain_info_no_cltrid.xml");
|
||||
|
||||
@@ -1023,16 +1023,16 @@ public class DomainTest {
|
||||
DesignatedContact.create(Type.TECH, contact4Key)),
|
||||
true);
|
||||
assertThat(domain.getRegistrant()).hasValue(contact1Key);
|
||||
assertThat(domain.getAdminContact()).isEqualTo(contact2Key);
|
||||
assertThat(domain.getBillingContact()).isEqualTo(contact3Key);
|
||||
assertThat(domain.getTechContact()).isEqualTo(contact4Key);
|
||||
assertThat(domain.getAdminContact()).hasValue(contact2Key);
|
||||
assertThat(domain.getBillingContact()).hasValue(contact3Key);
|
||||
assertThat(domain.getTechContact()).hasValue(contact4Key);
|
||||
|
||||
// Make sure everything gets nulled out.
|
||||
domain.setContactFields(ImmutableSet.of(), true);
|
||||
assertThat(domain.getRegistrant()).isEmpty();
|
||||
assertThat(domain.getAdminContact()).isNull();
|
||||
assertThat(domain.getBillingContact()).isNull();
|
||||
assertThat(domain.getTechContact()).isNull();
|
||||
assertThat(domain.getAdminContact()).isEmpty();
|
||||
assertThat(domain.getBillingContact()).isEmpty();
|
||||
assertThat(domain.getTechContact()).isEmpty();
|
||||
|
||||
// Make sure that changes don't affect the registrant unless requested.
|
||||
domain.setContactFields(
|
||||
@@ -1043,15 +1043,15 @@ public class DomainTest {
|
||||
DesignatedContact.create(Type.TECH, contact4Key)),
|
||||
false);
|
||||
assertThat(domain.getRegistrant()).isEmpty();
|
||||
assertThat(domain.getAdminContact()).isEqualTo(contact2Key);
|
||||
assertThat(domain.getBillingContact()).isEqualTo(contact3Key);
|
||||
assertThat(domain.getTechContact()).isEqualTo(contact4Key);
|
||||
assertThat(domain.getAdminContact()).hasValue(contact2Key);
|
||||
assertThat(domain.getBillingContact()).hasValue(contact3Key);
|
||||
assertThat(domain.getTechContact()).hasValue(contact4Key);
|
||||
domain = domain.asBuilder().setRegistrant(Optional.of(contact1Key)).build();
|
||||
domain.setContactFields(ImmutableSet.of(), false);
|
||||
assertThat(domain.getRegistrant()).hasValue(contact1Key);
|
||||
assertThat(domain.getAdminContact()).isNull();
|
||||
assertThat(domain.getBillingContact()).isNull();
|
||||
assertThat(domain.getTechContact()).isNull();
|
||||
assertThat(domain.getAdminContact()).isEmpty();
|
||||
assertThat(domain.getBillingContact()).isEmpty();
|
||||
assertThat(domain.getTechContact()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -27,6 +27,7 @@ import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrarPo
|
||||
import static google.registry.testing.GsonSubject.assertAboutJson;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.gson.JsonObject;
|
||||
import google.registry.model.contact.Contact;
|
||||
import google.registry.model.domain.Domain;
|
||||
@@ -292,6 +293,20 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
|
||||
assertProperResponseForCatLol("cat.lol", "rdap_domain_no_contacts_with_remark.json");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidDomain_notLoggedIn_contactsShowRedacted_whenNoContactsExist() {
|
||||
// Even though the domain has no contacts, it still shows a full set of REDACTED fields through
|
||||
// RDAP.
|
||||
persistResource(
|
||||
loadByForeignKey(Domain.class, "cat.lol", clock.nowUtc())
|
||||
.get()
|
||||
.asBuilder()
|
||||
.setRegistrant(Optional.empty())
|
||||
.setContacts(ImmutableSet.of())
|
||||
.build());
|
||||
assertProperResponseForCatLol("cat.lol", "rdap_domain_no_contacts_exist_with_remark.json");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidDomain_loggedInAsOtherRegistrar_noContacts() {
|
||||
login("idnregistrar");
|
||||
|
||||
@@ -307,6 +307,25 @@ class DomainWhoisResponseTest {
|
||||
.isEqualTo(WhoisResponseResults.create(loadFile("whois_domain_no_registrant.txt"), 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getPlainTextOutputTest_noContacts() {
|
||||
DomainWhoisResponse domainWhoisResponse =
|
||||
new DomainWhoisResponse(
|
||||
domain
|
||||
.asBuilder()
|
||||
.setRegistrant(Optional.empty())
|
||||
.setContacts(ImmutableSet.of())
|
||||
.build(),
|
||||
false,
|
||||
"Please contact registrar",
|
||||
clock.nowUtc());
|
||||
assertThat(
|
||||
domainWhoisResponse.getResponse(
|
||||
false,
|
||||
"Doodle Disclaimer\nI exist so that carriage return\nin disclaimer can be tested."))
|
||||
.isEqualTo(WhoisResponseResults.create(loadFile("whois_domain_no_contacts.txt"), 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getPlainTextOutputTest_registrarAbuseInfoMissing() {
|
||||
persistResource(abuseContact.asBuilder().setVisibleInDomainWhoisAsAbuse(false).build());
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<domain:infData
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example.tld</domain:name>
|
||||
<domain:roid>%ROID%</domain:roid>
|
||||
<domain:status s="ok"/>
|
||||
<domain:ns>
|
||||
<domain:hostObj>ns1.example.tld</domain:hostObj>
|
||||
<domain:hostObj>ns1.example.net</domain:hostObj>
|
||||
</domain:ns>
|
||||
<domain:host>ns1.example.tld</domain:host>
|
||||
<domain:host>ns2.example.tld</domain:host>
|
||||
<domain:clID>NewRegistrar</domain:clID>
|
||||
<domain:crID>TheRegistrar</domain:crID>
|
||||
<domain:crDate>1999-04-03T22:00:00.0Z</domain:crDate>
|
||||
<domain:upID>NewRegistrar</domain:upID>
|
||||
<domain:upDate>1999-12-03T09:00:00.0Z</domain:upDate>
|
||||
<domain:exDate>2005-04-03T22:00:00.0Z</domain:exDate>
|
||||
<domain:trDate>2000-04-08T09:00:00.0Z</domain:trDate>
|
||||
<domain:authInfo>
|
||||
<domain:pw>2fooBAR</domain:pw>
|
||||
</domain:authInfo>
|
||||
</domain:infData>
|
||||
</resData>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
||||
@@ -0,0 +1,263 @@
|
||||
{
|
||||
"rdapConformance": [
|
||||
"rdap_level_0",
|
||||
"icann_rdap_response_profile_0",
|
||||
"icann_rdap_technical_implementation_guide_0"
|
||||
],
|
||||
"objectClassName": "domain",
|
||||
"handle": "%DOMAIN_HANDLE_1%",
|
||||
"ldhName": "%DOMAIN_PUNYCODE_NAME_1%",
|
||||
"status": [
|
||||
"client delete prohibited",
|
||||
"client renew prohibited",
|
||||
"client transfer prohibited",
|
||||
"server update prohibited"
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
|
||||
"type": "application/rdap+json",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "https://rdap.example.com/withSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
|
||||
"type": "application/rdap+json",
|
||||
"rel": "related"
|
||||
},
|
||||
{
|
||||
"href": "https://rdap.example.com/withoutSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
|
||||
"type": "application/rdap+json",
|
||||
"rel": "related"
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
{
|
||||
"eventAction": "registration",
|
||||
"eventActor": "TheRegistrar",
|
||||
"eventDate": "1997-01-01T00:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"eventAction": "expiration",
|
||||
"eventDate": "2110-10-08T00:44:59.000Z"
|
||||
},
|
||||
{
|
||||
"eventAction": "last update of RDAP database",
|
||||
"eventDate": "2000-01-01T00:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"eventAction": "last changed",
|
||||
"eventDate": "2009-05-29T20:13:00.000Z"
|
||||
}
|
||||
],
|
||||
"nameservers": [
|
||||
{
|
||||
"objectClassName": "nameserver",
|
||||
"handle": "%NAMESERVER_HANDLE_1%",
|
||||
"ldhName": "%NAMESERVER_NAME_1%",
|
||||
"links": [
|
||||
{
|
||||
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
|
||||
"type": "application/rdap+json",
|
||||
"rel": "self"
|
||||
}
|
||||
],
|
||||
"remarks": [
|
||||
{
|
||||
"title": "Incomplete Data",
|
||||
"type": "object truncated due to unexplainable reasons",
|
||||
"description": ["Summary data only. For complete data, send a specific query for the object."]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"objectClassName": "nameserver",
|
||||
"handle": "%NAMESERVER_HANDLE_2%",
|
||||
"ldhName": "%NAMESERVER_NAME_2%",
|
||||
"links": [
|
||||
{
|
||||
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_2%",
|
||||
"type": "application/rdap+json",
|
||||
"rel": "self"
|
||||
}
|
||||
],
|
||||
"remarks": [
|
||||
{
|
||||
"title": "Incomplete Data",
|
||||
"type": "object truncated due to unexplainable reasons",
|
||||
"description": ["Summary data only. For complete data, send a specific query for the object."]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"secureDNS" : {
|
||||
"delegationSigned": true,
|
||||
"zoneSigned":true,
|
||||
"dsData":[
|
||||
{"algorithm":2,"digest":"DEADFACE","digestType":3,"keyTag":1}
|
||||
]
|
||||
},
|
||||
"entities": [
|
||||
{
|
||||
"objectClassName" : "entity",
|
||||
"handle" : "1",
|
||||
"roles" : ["registrar"],
|
||||
"links" : [
|
||||
{
|
||||
"rel" : "self",
|
||||
"href" : "https://example.tld/rdap/entity/1",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
"publicIds" : [
|
||||
{
|
||||
"type" : "IANA Registrar ID",
|
||||
"identifier" : "1"
|
||||
}
|
||||
],
|
||||
"vcardArray" : [
|
||||
"vcard",
|
||||
[
|
||||
["version", {}, "text", "4.0"],
|
||||
["fn", {}, "text", "%REGISTRAR_FULL_NAME_1%"]
|
||||
]
|
||||
],
|
||||
"entities" : [
|
||||
{
|
||||
"objectClassName":"entity",
|
||||
"roles":["abuse"],
|
||||
"status":["active"],
|
||||
"vcardArray": [
|
||||
"vcard",
|
||||
[
|
||||
["version",{},"text","4.0"],
|
||||
["fn",{},"text","Jake Doe"],
|
||||
["tel",{"type":["voice"]},"uri","tel:+1.2125551216"],
|
||||
["tel",{"type":["fax"]},"uri","tel:+1.2125551216"],
|
||||
["email",{},"text","jakedoe@example.com"]
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"remarks": [
|
||||
{
|
||||
"title": "Incomplete Data",
|
||||
"description": [
|
||||
"Summary data only. For complete data, send a specific query for the object."
|
||||
],
|
||||
"type": "object truncated due to unexplainable reasons"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"objectClassName":"entity",
|
||||
"handle":"",
|
||||
"remarks":[
|
||||
{
|
||||
"title":"REDACTED FOR PRIVACY",
|
||||
"type":"object redacted due to authorization",
|
||||
"description":[
|
||||
"Some of the data in this object has been removed.",
|
||||
"Contact personal data is visible only to the owning registrar."
|
||||
],
|
||||
"links":[
|
||||
{
|
||||
"href":"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
|
||||
"rel":"alternate",
|
||||
"type":"text/html"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title":"EMAIL REDACTED FOR PRIVACY",
|
||||
"type":"object redacted due to authorization",
|
||||
"description":[
|
||||
"Please query the RDDS service of the Registrar of Record identifies in this output for information on how to contact the Registrant of the queried domain name."
|
||||
]
|
||||
}
|
||||
],
|
||||
"roles":["registrant"],
|
||||
"vcardArray":[
|
||||
"vcard",
|
||||
[
|
||||
["version", {}, "text", "4.0"],
|
||||
["fn", {}, "text", ""]
|
||||
]
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"objectClassName": "entity",
|
||||
"handle": "",
|
||||
"roles":["administrative"],
|
||||
"remarks": [
|
||||
{
|
||||
"title":"REDACTED FOR PRIVACY",
|
||||
"type":"object redacted due to authorization",
|
||||
"description": [
|
||||
"Some of the data in this object has been removed.",
|
||||
"Contact personal data is visible only to the owning registrar."
|
||||
],
|
||||
"links":[
|
||||
{
|
||||
"href":"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
|
||||
"rel":"alternate",
|
||||
"type":"text/html"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title":"EMAIL REDACTED FOR PRIVACY",
|
||||
"type":"object redacted due to authorization",
|
||||
"description": [
|
||||
"Please query the RDDS service of the Registrar of Record identifies in this output for information on how to contact the Registrant of the queried domain name."
|
||||
]
|
||||
}
|
||||
],
|
||||
"vcardArray":[
|
||||
"vcard",
|
||||
[
|
||||
["version", {}, "text", "4.0"],
|
||||
["fn", {}, "text", ""]
|
||||
]
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"objectClassName":"entity",
|
||||
"handle":"",
|
||||
"remarks":[
|
||||
{
|
||||
"title":"REDACTED FOR PRIVACY",
|
||||
"type":"object redacted due to authorization",
|
||||
"description":[
|
||||
"Some of the data in this object has been removed.",
|
||||
"Contact personal data is visible only to the owning registrar."
|
||||
],
|
||||
"links":[
|
||||
{
|
||||
"href":"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
|
||||
"rel":"alternate",
|
||||
"type":"text/html"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description":[
|
||||
"Please query the RDDS service of the Registrar of Record identifies in this output for information on how to contact the Registrant of the queried domain name."
|
||||
],
|
||||
"title":"EMAIL REDACTED FOR PRIVACY",
|
||||
"type":"object redacted due to authorization"
|
||||
}
|
||||
],
|
||||
"roles": ["technical"],
|
||||
"vcardArray": [
|
||||
"vcard",
|
||||
[
|
||||
["version", {}, "text", "4.0"],
|
||||
["fn", {}, "text", ""]
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
Domain Name: example.tld
|
||||
Registry Domain ID: 3-TLD
|
||||
Registrar WHOIS Server: whois.nic.fakewhois.example
|
||||
Registrar URL: http://my.fake.url
|
||||
Updated Date: 2009-05-29T20:13:00Z
|
||||
Creation Date: 2000-10-08T00:45:00Z
|
||||
Registry Expiry Date: 2010-10-08T00:44:59Z
|
||||
Registrar: New Registrar
|
||||
Registrar IANA ID: 5555555
|
||||
Registrar Abuse Contact Email: jakedoe@theregistrar.com
|
||||
Registrar Abuse Contact Phone: +1.2125551216
|
||||
Domain Status: addPeriod https://icann.org/epp#addPeriod
|
||||
Domain Status: clientDeleteProhibited https://icann.org/epp#clientDeleteProhibited
|
||||
Domain Status: clientRenewProhibited https://icann.org/epp#clientRenewProhibited
|
||||
Domain Status: clientTransferProhibited https://icann.org/epp#clientTransferProhibited
|
||||
Domain Status: serverUpdateProhibited https://icann.org/epp#serverUpdateProhibited
|
||||
Domain Status: transferPeriod https://icann.org/epp#transferPeriod
|
||||
Name Server: ns01.exampleregistrar.tld
|
||||
Name Server: ns02.exampleregistrar.tld
|
||||
DNSSEC: signedDelegation
|
||||
URL of the ICANN Whois Inaccuracy Complaint Form: https://www.icann.org/wicf/
|
||||
>>> Last update of WHOIS database: 2009-05-29T20:15:00Z <<<
|
||||
|
||||
For more information on Whois status codes, please visit https://icann.org/epp
|
||||
|
||||
Doodle Disclaimer
|
||||
I exist so that carriage return
|
||||
in disclaimer can be tested.
|
||||
Reference in New Issue
Block a user