Remove WHOIS classes and configuration (#2859)

This is steps one and two of b/454947209

We already haven't been serving WHOIS for a while, so there's no point
in keeping the old code around. This can simplify some code paths in the
future (like, certain foreign-key-loads that are only used in WHOIS
queries).
This commit is contained in:
gbrodman
2025-10-27 18:57:25 +00:00
committed by GitHub
parent 19e03dbd2e
commit 6cd351ec7c
105 changed files with 19 additions and 8623 deletions
@@ -47,14 +47,12 @@ public final class RegistryTestServer {
public static final ImmutableList<Route> ROUTES =
ImmutableList.of(
// Frontend Services
route("/whois/*", FrontendServlet.class),
route("/rdap/*", FrontendServlet.class),
route("/check", FrontendServlet.class),
route("/console-api/*", FrontendTestServlet.class),
// Proxy Services
route("/_dr/epp", FrontendServlet.class),
route("/_dr/whois", FrontendServlet.class),
// Registry Data Escrow (RDE)
route("/_dr/cron/rdeCreate", BackendServlet.class),
@@ -1,68 +0,0 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.ui.server;
import static com.google.common.truth.Truth.assertThat;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.jupiter.api.Assertions.assertThrows;
import google.registry.testing.CertificateSamples;
import google.registry.ui.forms.FormFieldException;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link RegistrarFormFields}. */
class RegistrarFormFieldsTest {
@Test
void testValidCertificate_doesntThrowError() {
assertThat(RegistrarFormFields.CLIENT_CERTIFICATE_FIELD.convert(CertificateSamples.SAMPLE_CERT))
.hasValue(CertificateSamples.SAMPLE_CERT);
}
@Test
void testBadCertificate_throwsFfe() {
FormFieldException thrown =
assertThrows(
FormFieldException.class,
() -> RegistrarFormFields.CLIENT_CERTIFICATE_FIELD.convert("palfun"));
assertThat(
thrown,
equalTo(
new FormFieldException("Invalid X.509 PEM certificate")
.propagate("clientCertificate")));
}
@Test
void testValidCertificateHash_doesntThrowError() {
assertThat(
RegistrarFormFields.CLIENT_CERTIFICATE_HASH_FIELD.convert(
CertificateSamples.SAMPLE_CERT_HASH))
.hasValue(CertificateSamples.SAMPLE_CERT_HASH);
}
@Test
void testBadCertificateHash_throwsFfe() {
FormFieldException thrown =
assertThrows(
FormFieldException.class,
() -> RegistrarFormFields.CLIENT_CERTIFICATE_HASH_FIELD.convert("~~~"));
assertThat(
thrown,
equalTo(
new FormFieldException("Field must contain a base64 value.")
.propagate("clientCertificateHash")));
}
}
@@ -1,371 +0,0 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.whois;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.loadRegistrar;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static google.registry.whois.WhoisTestData.loadFile;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import google.registry.model.contact.Contact;
import google.registry.model.contact.ContactAddress;
import google.registry.model.contact.ContactPhoneNumber;
import google.registry.model.contact.PostalInfo;
import google.registry.model.domain.DesignatedContact;
import google.registry.model.domain.Domain;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.secdns.DomainDsData;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.Host;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.persistence.VKey;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.testing.FakeClock;
import google.registry.whois.WhoisResponse.WhoisResponseResults;
import java.util.Optional;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link DomainWhoisResponse}. */
class DomainWhoisResponseTest {
@RegisterExtension
final JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
private Host host1;
private Host host2;
private RegistrarPoc abuseContact;
private Contact adminContact;
private Contact registrant;
private Contact techContact;
private Domain domain;
private final FakeClock clock = new FakeClock(DateTime.parse("2009-05-29T20:15:00Z"));
@BeforeEach
void beforeEach() {
// Update the registrar to have an IANA ID.
Registrar registrar =
persistResource(
loadRegistrar("NewRegistrar")
.asBuilder()
.setUrl("http://my.fake.url")
.setIanaIdentifier(5555555L)
.build());
abuseContact =
persistResource(
new RegistrarPoc.Builder()
.setRegistrar(registrar)
.setName("Jake Doe")
.setEmailAddress("jakedoe@theregistrar.com")
.setPhoneNumber("+1.2125551216")
.setVisibleInDomainWhoisAsAbuse(true)
.build());
createTld("tld");
host1 =
persistResource(
new Host.Builder()
.setHostName("ns01.exampleregistrar.tld")
.setRepoId("1-ROID")
.build());
host2 =
persistResource(
new Host.Builder()
.setHostName("ns02.exampleregistrar.tld")
.setRepoId("2-ROID")
.build());
registrant =
persistResource(
new Contact.Builder()
.setContactId("5372808-ERL")
.setRepoId("4-ROID")
.setCreationRegistrarId("NewRegistrar")
.setPersistedCurrentSponsorRegistrarId("NewRegistrar")
.setLocalizedPostalInfo(
new PostalInfo.Builder()
.setType(PostalInfo.Type.LOCALIZED)
.setName("SHOULD NOT BE USED")
.setOrg("SHOULD NOT BE USED")
.setAddress(
new ContactAddress.Builder()
.setStreet(ImmutableList.of("123 EXAMPLE STREET"))
.setCity("ANYTOWN")
.setState("AP")
.setZip("A1A1A1")
.setCountryCode("EX")
.build())
.build())
.setInternationalizedPostalInfo(
new PostalInfo.Builder()
.setType(PostalInfo.Type.INTERNATIONALIZED)
.setName("EXAMPLE REGISTRANT")
.setOrg("Tom & Jerry Corp.")
.setAddress(
new ContactAddress.Builder()
.setStreet(ImmutableList.of("123 EXAMPLE STREET"))
.setCity("ANYTOWN")
.setState("AP")
.setZip("A1A1A1")
.setCountryCode("EX")
.build())
.build())
.setVoiceNumber(
new ContactPhoneNumber.Builder()
.setPhoneNumber("+1.5555551212")
.setExtension("1234")
.build())
.setFaxNumber(
new ContactPhoneNumber.Builder()
.setPhoneNumber("+1.5555551213")
.setExtension("4321")
.build())
.setEmailAddress("EMAIL@EXAMPLE.tld")
.build());
adminContact =
persistResource(
new Contact.Builder()
.setContactId("5372809-ERL")
.setRepoId("5-ROID")
.setCreationRegistrarId("NewRegistrar")
.setPersistedCurrentSponsorRegistrarId("NewRegistrar")
.setLocalizedPostalInfo(
new PostalInfo.Builder()
.setType(PostalInfo.Type.LOCALIZED)
.setName("SHOULD NOT BE USED")
.setOrg("SHOULD NOT BE USED")
.setAddress(
new ContactAddress.Builder()
.setStreet(ImmutableList.of("123 EXAMPLE STREET"))
.setCity("ANYTOWN")
.setState("AP")
.setZip("A1A1A1")
.setCountryCode("EX")
.build())
.build())
.setInternationalizedPostalInfo(
new PostalInfo.Builder()
.setType(PostalInfo.Type.INTERNATIONALIZED)
.setName("EXAMPLE REGISTRANT ADMINISTRATIVE")
.setOrg("EXAMPLE REGISTRANT ORGANIZATION")
.setAddress(
new ContactAddress.Builder()
.setStreet(ImmutableList.of("123 EXAMPLE STREET"))
.setCity("ANYTOWN")
.setState("AP")
.setZip("A1A1A1")
.setCountryCode("EX")
.build())
.build())
.setVoiceNumber(
new ContactPhoneNumber.Builder()
.setPhoneNumber("+1.5555551212")
.setExtension("1234")
.build())
.setFaxNumber(
new ContactPhoneNumber.Builder().setPhoneNumber("+1.5555551213").build())
.setEmailAddress("EMAIL@EXAMPLE.tld")
.build());
techContact =
persistResource(
new Contact.Builder()
.setContactId("5372811-ERL")
.setRepoId("6-ROID")
.setCreationRegistrarId("NewRegistrar")
.setPersistedCurrentSponsorRegistrarId("NewRegistrar")
.setLocalizedPostalInfo(
new PostalInfo.Builder()
.setType(PostalInfo.Type.LOCALIZED)
.setName("SHOULD NOT BE USED")
.setOrg("SHOULD NOT BE USED")
.setAddress(
new ContactAddress.Builder()
.setStreet(ImmutableList.of("123 EXAMPLE STREET"))
.setCity("ANYTOWN")
.setState("AP")
.setZip("A1A1A1")
.setCountryCode("EX")
.build())
.build())
.setInternationalizedPostalInfo(
new PostalInfo.Builder()
.setType(PostalInfo.Type.INTERNATIONALIZED)
.setName("EXAMPLE REGISTRAR TECHNICAL")
.setOrg("EXAMPLE REGISTRAR LLC")
.setAddress(
new ContactAddress.Builder()
.setStreet(ImmutableList.of("123 EXAMPLE STREET"))
.setCity("ANYTOWN")
.setState("AP")
.setZip("A1A1A1")
.setCountryCode("EX")
.build())
.build())
.setVoiceNumber(
new ContactPhoneNumber.Builder()
.setPhoneNumber("+1.1235551234")
.setExtension("1234")
.build())
.setFaxNumber(
new ContactPhoneNumber.Builder()
.setPhoneNumber("+1.5555551213")
.setExtension("93")
.build())
.setEmailAddress("EMAIL@EXAMPLE.tld")
.build());
VKey<Host> host1VKey = host1.createVKey();
VKey<Host> host2VKey = host2.createVKey();
VKey<Contact> registrantResourceKey = registrant.createVKey();
VKey<Contact> adminResourceKey = adminContact.createVKey();
VKey<Contact> techResourceKey = techContact.createVKey();
String repoId = "3-TLD";
domain =
persistResource(
new Domain.Builder()
.setDomainName("example.tld")
.setRepoId(repoId)
.setCreationRegistrarId("NewRegistrar")
.setPersistedCurrentSponsorRegistrarId("NewRegistrar")
.setLastEppUpdateTime(DateTime.parse("2009-05-29T20:13:00Z"))
.setCreationTimeForTest(DateTime.parse("2000-10-08T00:45:00Z"))
.setRegistrationExpirationTime(DateTime.parse("2010-10-08T00:44:59Z"))
.setStatusValues(
ImmutableSet.of(
StatusValue.CLIENT_DELETE_PROHIBITED,
StatusValue.CLIENT_RENEW_PROHIBITED,
StatusValue.CLIENT_TRANSFER_PROHIBITED,
StatusValue.SERVER_UPDATE_PROHIBITED))
.setRegistrant(Optional.of(registrantResourceKey))
.setContacts(
ImmutableSet.of(
DesignatedContact.create(DesignatedContact.Type.ADMIN, adminResourceKey),
DesignatedContact.create(DesignatedContact.Type.TECH, techResourceKey)))
.setNameservers(ImmutableSet.of(host1VKey, host2VKey))
.setDsData(ImmutableSet.of(DomainDsData.create(1, 2, 3, "deadface")))
.setGracePeriods(
ImmutableSet.of(
GracePeriod.create(
GracePeriodStatus.ADD, repoId, END_OF_TIME, "NewRegistrar", null),
GracePeriod.create(
GracePeriodStatus.TRANSFER, repoId, END_OF_TIME, "NewRegistrar", null)))
.build());
}
@Test
void getPlainTextOutputTest() {
DomainWhoisResponse domainWhoisResponse =
new DomainWhoisResponse(domain, 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.txt"), 1));
}
@Test
void getPlainTextOutputTest_noRegistrant() {
DomainWhoisResponse domainWhoisResponse =
new DomainWhoisResponse(
domain.asBuilder().setRegistrant(Optional.empty()).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_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());
DomainWhoisResponse domainWhoisResponse =
new DomainWhoisResponse(domain, false, "Please contact registrar", clock.nowUtc());
assertThat(
domainWhoisResponse.getResponse(false, "Footer"))
.isEqualTo(
WhoisResponseResults.create(
loadFile("whois_domain_registrar_abuse_info_missing.txt"), 1));
}
@Test
void getPlainTextOutputTest_fullOutput() {
DomainWhoisResponse domainWhoisResponse =
new DomainWhoisResponse(domain, true, "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_full_output.txt"), 1));
}
@Test
void addImplicitOkStatusTest() {
DomainWhoisResponse domainWhoisResponse =
new DomainWhoisResponse(
domain.asBuilder().setStatusValues(null).build(),
false,
"Contact the registrar",
clock.nowUtc());
assertThat(
domainWhoisResponse
.getResponse(
false,
"""
Doodle Disclaimer
I exist so that carriage return
in disclaimer can be tested.""")
.plainTextOutput())
.contains("Domain Status: ok");
}
}
@@ -1,127 +0,0 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.whois;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.loadRegistrar;
import static google.registry.testing.DatabaseHelper.persistNewRegistrar;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.whois.WhoisTestData.loadFile;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.net.InetAddresses;
import google.registry.model.domain.Domain;
import google.registry.model.host.Host;
import google.registry.model.registrar.Registrar;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeClock;
import google.registry.whois.WhoisResponse.WhoisResponseResults;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link NameserverWhoisResponse}. */
class NameserverWhoisResponseTest {
@RegisterExtension
final JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
private Host host1;
private Host host2;
private Host host3;
private final FakeClock clock = new FakeClock(DateTime.parse("2009-05-29T20:15:00Z"));
@BeforeEach
void beforeEach() {
persistNewRegistrar("example", "Hänsel & Gretel Registrar, Inc.", Registrar.Type.REAL, 8L);
persistResource(loadRegistrar("example").asBuilder().setUrl("http://my.fake.url").build());
createTld("tld");
Domain domain = persistResource(DatabaseHelper.newDomain("zobo.tld"));
host1 =
new Host.Builder()
.setHostName("ns1.example.tld")
.setPersistedCurrentSponsorRegistrarId("example")
.setInetAddresses(
ImmutableSet.of(
InetAddresses.forString("192.0.2.123"),
InetAddresses.forString("2001:0DB8::1")))
.setRepoId("1-EXAMPLE")
.build();
host2 =
new Host.Builder()
.setHostName("ns2.example.tld")
.setPersistedCurrentSponsorRegistrarId("example")
.setInetAddresses(
ImmutableSet.of(
InetAddresses.forString("192.0.2.123"),
InetAddresses.forString("2001:0DB8::1")))
.setRepoId("2-EXAMPLE")
.build();
host3 =
new Host.Builder()
.setHostName("ns1.zobo.tld")
.setSuperordinateDomain(domain.createVKey())
.setPersistedCurrentSponsorRegistrarId("example")
.setInetAddresses(
ImmutableSet.of(
InetAddresses.forString("192.0.2.123"),
InetAddresses.forString("2001:0DB8::1")))
.setRepoId("3-EXAMPLE")
.build();
}
@Test
void testGetTextOutput() {
NameserverWhoisResponse nameserverWhoisResponse =
new NameserverWhoisResponse(host1, clock.nowUtc());
assertThat(
nameserverWhoisResponse.getResponse(
false,
"Doodle Disclaimer\nI exist so that carriage return\nin disclaimer can be tested."))
.isEqualTo(WhoisResponseResults.create(loadFile("whois_nameserver.txt"), 1));
}
@Test
void testGetMultipleNameserversResponse() {
NameserverWhoisResponse nameserverWhoisResponse =
new NameserverWhoisResponse(ImmutableList.of(host1, host2), clock.nowUtc());
assertThat(
nameserverWhoisResponse.getResponse(
false,
"Doodle Disclaimer\nI exist so that carriage return\nin disclaimer can be tested."))
.isEqualTo(WhoisResponseResults.create(loadFile("whois_multiple_nameservers.txt"), 2));
}
@Test
void testSubordinateDomains() {
NameserverWhoisResponse nameserverWhoisResponse =
new NameserverWhoisResponse(host3, clock.nowUtc());
assertThat(
nameserverWhoisResponse.getResponse(
false,
"Doodle Disclaimer\nI exist so that carriage return\nin disclaimer can be tested."))
.isEqualTo(WhoisResponseResults.create(loadFile("whois_subord_nameserver.txt"), 1));
}
}
@@ -1,138 +0,0 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.whois;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatabaseHelper.persistNewRegistrar;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.testing.DatabaseHelper.persistResources;
import static google.registry.whois.WhoisTestData.loadFile;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.testing.FakeClock;
import google.registry.whois.WhoisResponse.WhoisResponseResults;
import org.joda.time.DateTime;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link RegistrarWhoisResponse}. */
class RegistrarWhoisResponseTest {
@RegisterExtension
final JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
private final FakeClock clock = new FakeClock(DateTime.parse("2009-05-29T20:15:00Z"));
@Test
void getTextOutputTest() {
Registrar registrar =
new Registrar.Builder()
.setRegistrarId("exregistrar")
.setRegistrarName("Example Registrar, Inc.")
.setType(Registrar.Type.REAL)
.setIanaIdentifier(8L)
.setState(Registrar.State.ACTIVE)
.setLocalizedAddress(
new RegistrarAddress.Builder()
.setStreet(ImmutableList.of("1234 Admiralty Way"))
.setCity("Marina del Rey")
.setState("CA")
.setZip("90292")
.setCountryCode("US")
.build())
.setPhoneNumber("+1.3105551212")
.setFaxNumber("+1.3105551213")
.setEmailAddress("registrar@example.tld")
.setWhoisServer("whois.example-registrar.tld")
.setUrl("http://my.fake.url")
.build();
// Use the registrar key for contacts' parent.
ImmutableList<RegistrarPoc> contacts =
ImmutableList.of(
new RegistrarPoc.Builder()
.setRegistrar(registrar)
.setName("Joe Registrar")
.setEmailAddress("joeregistrar@example-registrar.tld")
.setPhoneNumber("+1.3105551213")
.setFaxNumber("+1.3105551213")
.setTypes(ImmutableSet.of(RegistrarPoc.Type.ADMIN))
.setVisibleInWhoisAsAdmin(true)
.setVisibleInWhoisAsTech(false)
.build(),
new RegistrarPoc.Builder()
.setRegistrar(registrar)
.setName("John Doe")
.setEmailAddress("johndoe@example-registrar.tld")
.setPhoneNumber("+1.1111111111")
.setFaxNumber("+1.1111111111")
.setTypes(ImmutableSet.of(RegistrarPoc.Type.ADMIN))
.build(),
new RegistrarPoc.Builder()
.setRegistrar(registrar)
.setName("Jane Registrar")
.setEmailAddress("janeregistrar@example-registrar.tld")
.setPhoneNumber("+1.3105551214")
.setFaxNumber("+1.3105551213")
.setTypes(ImmutableSet.of(RegistrarPoc.Type.ADMIN))
.setVisibleInWhoisAsAdmin(true)
.build(),
new RegistrarPoc.Builder()
.setRegistrar(registrar)
.setName("Jane Doe")
.setEmailAddress("janedoe@example-registrar.tld")
.setPhoneNumber("+1.1111111112")
.setFaxNumber("+1.1111111112")
.setTypes(ImmutableSet.of(RegistrarPoc.Type.TECH))
.build(),
new RegistrarPoc.Builder()
.setRegistrar(registrar)
.setName("Bonnie & Clyde")
.setEmailAddress("johngeek@example-registrar.tld")
.setPhoneNumber("+1.3105551215")
.setFaxNumber("+1.3105551216")
.setTypes(ImmutableSet.of(RegistrarPoc.Type.TECH))
.setVisibleInWhoisAsTech(true)
.build());
persistResource(registrar);
persistResources(contacts);
RegistrarWhoisResponse registrarWhoisResponse =
new RegistrarWhoisResponse(registrar, clock.nowUtc());
assertThat(
registrarWhoisResponse.getResponse(
false,
"Doodle Disclaimer\nI exist so that carriage return\nin disclaimer can be tested."))
.isEqualTo(WhoisResponseResults.create(loadFile("whois_registrar.txt"), 1));
}
@Test
void testSetOfFields() {
Registrar registrar =
persistNewRegistrar("exregistrar", "Ex-Registrar", Registrar.Type.REAL, 8L);
RegistrarWhoisResponse registrarWhoisResponse =
new RegistrarWhoisResponse(registrar, clock.nowUtc());
// Just make sure this doesn't NPE.
registrarWhoisResponse.getResponse(
false, "Doodle Disclaimer\nI exist so that carriage return\nin disclaimer can be tested.");
}
}
@@ -1,679 +0,0 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.whois;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.bsa.persistence.BsaTestingUtils.persistBsaLabel;
import static google.registry.model.EppResourceUtils.loadByForeignKeyByCacheIfEnabled;
import static google.registry.model.registrar.Registrar.State.ACTIVE;
import static google.registry.model.registrar.Registrar.Type.PDT;
import static google.registry.model.tld.Tlds.getTlds;
import static google.registry.testing.DatabaseHelper.createTlds;
import static google.registry.testing.DatabaseHelper.loadRegistrar;
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.testing.DatabaseHelper.persistResources;
import static google.registry.testing.FullFieldsTestEntityHelper.makeDomain;
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrar;
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrarPocs;
import static google.registry.whois.WhoisTestData.loadFile;
import static jakarta.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import static jakarta.servlet.http.HttpServletResponse.SC_NOT_FOUND;
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableSet;
import com.google.common.net.InetAddresses;
import google.registry.model.contact.Contact;
import google.registry.model.domain.Domain;
import google.registry.model.eppcommon.Trid;
import google.registry.model.host.Host;
import google.registry.model.registrar.Registrar;
import google.registry.model.tld.Tld;
import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferStatus;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import google.registry.testing.FakeSleeper;
import google.registry.testing.FullFieldsTestEntityHelper;
import google.registry.testing.TestCacheExtension;
import google.registry.util.Retrier;
import google.registry.whois.WhoisMetrics.WhoisMetric;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.time.Duration;
import java.util.Optional;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link WhoisAction}. */
public class WhoisActionTest {
private final FakeClock clock = new FakeClock(DateTime.parse("2009-06-29T20:13:00Z"));
@RegisterExtension
final JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
@RegisterExtension
public final TestCacheExtension testCacheExtension =
new TestCacheExtension.Builder()
.withEppResourceCache(Duration.ofDays(1))
.withForeignKeyCache(Duration.ofDays(1))
.build();
private final FakeResponse response = new FakeResponse();
private WhoisAction newWhoisAction(String input) {
WhoisAction whoisAction = new WhoisAction();
whoisAction.clock = clock;
whoisAction.input = new StringReader(input);
whoisAction.response = response;
whoisAction.whoisReader =
new WhoisReader(
WhoisCommandFactory.createCached(), "Please contact registrar", "Blocked by BSA: %s");
whoisAction.whoisMetrics = new WhoisMetrics();
whoisAction.metricBuilder = WhoisMetric.builderForRequest(clock);
whoisAction.disclaimer =
"Doodle Disclaimer\nI exist so that carriage return\nin disclaimer can be tested.";
whoisAction.retrier = new Retrier(new FakeSleeper(clock), 3);
return whoisAction;
}
@BeforeEach
void setUp() {
createTlds("lol", "xn--q9jyb4c", "1.test");
}
@Test
void testRun_badRequest_stillSends200() {
newWhoisAction("\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_no_command.txt"));
}
private static Domain makeDomainWithRegistrar(Registrar registrar) {
return makeDomain(
"cat.lol",
persistResource(
FullFieldsTestEntityHelper.makeContact("5372808-ERL", "Goblin Market", "lol@cat.lol")),
persistResource(
FullFieldsTestEntityHelper.makeContact("5372808-IRL", "Santa Claus", "BOFH@cat.lol")),
persistResource(
FullFieldsTestEntityHelper.makeContact("5372808-TRL", "The Raven", "bog@cat.lol")),
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4")),
persistResource(
FullFieldsTestEntityHelper.makeHost("ns2.cat.lol", "bad:f00d:cafe::15:beef")),
registrar);
}
@Test
void testRun_domainQuery_works() {
Registrar registrar =
persistResource(makeRegistrar("evilregistrar", "Yes Virginia", ACTIVE));
persistResource(makeDomainWithRegistrar(registrar));
persistResources(makeRegistrarPocs(registrar));
newWhoisAction("domain cat.lol\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_domain.txt"));
}
@Test
void testRun_domainQuery_usesCache() {
Registrar registrar =
persistResource(makeRegistrar("evilregistrar", "Yes Virginia", ACTIVE));
persistResource(makeDomainWithRegistrar(registrar));
persistResources(makeRegistrarPocs(registrar));
// Populate the cache for both the domain and contact.
Domain domain = loadByForeignKeyByCacheIfEnabled(Domain.class, "cat.lol", clock.nowUtc()).get();
Contact contact =
loadByForeignKeyByCacheIfEnabled(Contact.class, "5372808-ERL", clock.nowUtc()).get();
// Make a change to the domain and contact that won't be seen because the cache will be hit.
persistResource(domain.asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
persistResource(
contact
.asBuilder()
.setInternationalizedPostalInfo(
contact
.getInternationalizedPostalInfo()
.asBuilder()
.setOrg("Two by Two, Hands Blue Inc.")
.build())
.build());
newWhoisAction("domain cat.lol\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_domain.txt"));
}
@Test
void testRun_domainQuery_registeredDomainUnaffectedByBsa() {
persistResource(
Tld.get("lol")
.asBuilder()
.setBsaEnrollStartTime(Optional.of(clock.nowUtc().minusDays(1)))
.build());
persistBsaLabel("cat");
Registrar registrar = persistResource(makeRegistrar("evilregistrar", "Yes Virginia", ACTIVE));
persistResource(makeDomainWithRegistrar(registrar));
persistResources(makeRegistrarPocs(registrar));
newWhoisAction("domain cat.lol\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_domain.txt"));
}
@Test
void testRun_domainQuery_unregisteredDomainShowBsaMessage() {
persistResource(
Tld.get("lol")
.asBuilder()
.setBsaEnrollStartTime(Optional.of(clock.nowUtc().minusDays(1)))
.build());
persistBsaLabel("cat");
newWhoisAction("domain cat.lol\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_domain_blocked_by_bsa.txt"));
}
@Test
void testRun_domainAfterTransfer_hasUpdatedEppTimeAndClientId() {
Registrar registrar = persistResource(makeRegistrar("TheRegistrar", "Yes Virginia", ACTIVE));
persistResource(
makeDomainWithRegistrar(registrar)
.asBuilder()
.setTransferData(
new DomainTransferData.Builder()
.setGainingRegistrarId("TheRegistrar")
.setLosingRegistrarId("NewRegistrar")
.setTransferRequestTime(DateTime.parse("2009-05-29T20:13:00Z"))
.setPendingTransferExpirationTime(DateTime.parse("2010-03-01T00:00:00Z"))
.setTransferStatus(TransferStatus.PENDING)
.setTransferRequestTrid(Trid.create("client-trid", "server-trid"))
.build())
.build());
persistResources(makeRegistrarPocs(registrar));
clock.setTo(DateTime.parse("2011-01-01T00:00:00Z"));
newWhoisAction("domain cat.lol\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_transferred_domain.txt"));
}
@Test
void testRun_idnDomain_works() {
Registrar registrar = persistResource(makeRegistrar(
"evilregistrar", "Yes Virginia", ACTIVE));
persistResource(
makeDomain(
"cat.みんな",
persistResource(
FullFieldsTestEntityHelper.makeContact("5372808-ERL", "(◕‿◕)", "lol@cat.みんな")),
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-IRL", "Santa Claus", "BOFH@cat.みんな")),
persistResource(
FullFieldsTestEntityHelper.makeContact("5372808-TRL", "The Raven", "bog@cat.みんな")),
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.みんな", "1.2.3.4")),
persistResource(
FullFieldsTestEntityHelper.makeHost("ns2.cat.みんな", "bad:f00d:cafe::15:beef")),
registrar));
persistResources(makeRegistrarPocs(registrar));
newWhoisAction("domain cat.みんな\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_idn_punycode.txt"));
}
@Test
void testRun_punycodeDomain_works() {
Registrar registrar = persistResource(makeRegistrar(
"evilregistrar", "Yes Virginia", ACTIVE));
persistResource(
makeDomain(
"cat.みんな",
persistResource(
FullFieldsTestEntityHelper.makeContact("5372808-ERL", "(◕‿◕)", "lol@cat.みんな")),
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-IRL", "Santa Claus", "BOFH@cat.みんな")),
persistResource(
FullFieldsTestEntityHelper.makeContact("5372808-TRL", "The Raven", "bog@cat.みんな")),
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.みんな", "1.2.3.4")),
persistResource(
FullFieldsTestEntityHelper.makeHost("ns2.cat.みんな", "bad:f00d:cafe::15:beef")),
registrar));
persistResources(makeRegistrarPocs(registrar));
newWhoisAction("domain cat.xn--q9jyb4c\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_idn_punycode.txt"));
}
@Test
void testRun_domainNotFound_returns200OkAndPlainTextResponse() {
newWhoisAction("domain cat.lol\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_domain_not_found.txt"));
}
@Test
void testRun_domainNotFound_usesCache() {
// Populate the cache with the nonexistence of this domain.
assertThat(loadByForeignKeyByCacheIfEnabled(Domain.class, "cat.lol", clock.nowUtc())).isEmpty();
// Add a new valid cat.lol domain that won't be found because the cache will be hit instead.
persistActiveDomain("cat.lol");
newWhoisAction("domain cat.lol\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_domain_not_found.txt"));
}
// todo (b/27378695): reenable or delete this test
@Disabled
@Test
void testRun_domainInTestTld_isConsideredNotFound() {
persistResource(Tld.get("lol").asBuilder().setTldType(Tld.TldType.TEST).build());
Registrar registrar = persistResource(makeRegistrar(
"evilregistrar", "Yes Virginia", ACTIVE));
persistResource(
makeDomain(
"cat.lol",
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-ERL", "Goblin Market", "lol@cat.lol")),
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-IRL", "Santa Claus", "BOFH@cat.lol")),
persistResource(
FullFieldsTestEntityHelper.makeContact("5372808-TRL", "The Raven", "bog@cat.lol")),
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4")),
persistResource(
FullFieldsTestEntityHelper.makeHost("ns2.cat.lol", "bad:f00d:cafe::15:beef")),
registrar));
persistResources(makeRegistrarPocs(registrar));
newWhoisAction("domain cat.lol\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_domain_not_found.txt"));
}
@Test
void testRun_domainFlaggedAsDeletedInDatabase_isConsideredNotFound() {
Registrar registrar;
persistResource(
makeDomain(
"cat.lol",
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-ERL", "Peter Murphy", "lol@cat.lol")),
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-IRL", "Santa Claus", "BOFH@cat.lol")),
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-TRL", "The Raven", "bog@cat.lol")),
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4")),
persistResource(
FullFieldsTestEntityHelper.makeHost("ns2.cat.lol", "bad:f00d:cafe::15:beef")),
persistResource(registrar = makeRegistrar("example", "Example Registrar", ACTIVE)))
.asBuilder()
.setDeletionTime(clock.nowUtc().minusDays(1))
.build());
persistResources(makeRegistrarPocs(registrar));
newWhoisAction("domain cat.lol\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_domain_not_found.txt"));
}
/**
* Create a deleted domain and an active domain with the same label, and make sure only the active
* one is returned.
*/
@Test
void testRun_domainDeletedThenRecreated_isFound() {
Registrar registrar;
Domain domain1 =
persistResource(
makeDomain(
"cat.lol",
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-ERL", "Peter Murphy", "lol@cat.lol")),
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-IRL", "Santa Claus", "BOFH@cat.lol")),
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-TRL", "The Raven", "bog@cat.lol")),
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4")),
persistResource(
FullFieldsTestEntityHelper.makeHost(
"ns2.cat.lol", "bad:f00d:cafe::15:beef")),
persistResource(makeRegistrar("example", "Example Registrar", ACTIVE)))
.asBuilder()
.setCreationTimeForTest(clock.nowUtc().minusDays(2))
.setDeletionTime(clock.nowUtc().minusDays(1))
.build());
Domain domain2 =
persistResource(
makeDomain(
"cat.lol",
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372809-ERL", "Mrs. Alice Crypto", "alice@example.lol")),
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372809-IRL", "Mr. Bob Crypto", "bob@example.lol")),
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372809-TRL", "Dr. Pablo", "pmy@example.lol")),
persistResource(
FullFieldsTestEntityHelper.makeHost("ns1.google.lol", "9.9.9.9")),
persistResource(
FullFieldsTestEntityHelper.makeHost("ns2.google.lol", "4311::f143")),
persistResource(
registrar = makeRegistrar("example", "Example Registrar", ACTIVE)))
.asBuilder()
.setCreationTimeForTest(clock.nowUtc())
.build());
persistResources(makeRegistrarPocs(registrar));
assertThat(domain1.getRepoId()).isNotEqualTo(domain2.getRepoId());
newWhoisAction("domain cat.lol\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).contains("ns1.google.lol");
}
@Test
void testRun_nameserverQuery_works() {
persistResource(loadRegistrar("TheRegistrar").asBuilder().setUrl("http://my.fake.url").build());
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4"));
newWhoisAction("nameserver ns1.cat.lol\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_nameserver.txt"));
}
@Test
void testRun_ipv6_displaysInCollapsedReadableFormat() {
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "bad:f00d:cafe::15:beef"));
newWhoisAction("nameserver ns1.cat.lol\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).contains("ns1.cat.lol");
// The most important thing this tests is that the outputted address is compressed!
assertThat(response.getPayload()).contains("bad:f00d:cafe::15:beef");
assertThat(response.getPayload()).doesNotContain("bad:f00d:cafe:0:0:0:15:beef");
}
@Test
void testRun_idnNameserver_works() {
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.みんな", "1.2.3.4"));
newWhoisAction("nameserver ns1.cat.みんな\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).contains("ns1.cat.xn--q9jyb4c");
assertThat(response.getPayload()).contains("1.2.3.4");
}
@Test
void testRun_nameserver_usesCache() {
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.xn--q9jyb4c", "1.2.3.4"));
// Populate the cache.
Host host =
loadByForeignKeyByCacheIfEnabled(Host.class, "ns1.cat.xn--q9jyb4c", clock.nowUtc()).get();
// Make a change to the persisted host that won't be seen because the cache will be hit.
persistResource(
host.asBuilder()
.setInetAddresses(ImmutableSet.of(InetAddresses.forString("8.8.8.8")))
.build());
newWhoisAction("nameserver ns1.cat.みんな\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).contains("ns1.cat.xn--q9jyb4c");
assertThat(response.getPayload()).contains("1.2.3.4");
}
@Test
void testRun_punycodeNameserver_works() {
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.みんな", "1.2.3.4"));
newWhoisAction("nameserver ns1.cat.xn--q9jyb4c\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).contains("ns1.cat.xn--q9jyb4c");
assertThat(response.getPayload()).contains("1.2.3.4");
}
@Test
void testRun_nameserverNotFound_returns200AndText() {
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4"));
newWhoisAction("nameserver ns1.cat.lulz\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_nameserver_not_found.txt"));
}
@Test
void testRun_nameserverFlaggedAsDeletedInDatabase_doesntGetLeaked() {
persistResource(
FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4")
.asBuilder()
.setDeletionTime(clock.nowUtc().minusDays(1))
.build());
newWhoisAction("nameserver ns1.cat.lol\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_nameserver_not_found.txt"));
}
@Test
void testRun_ipNameserverLookup_works() {
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4"));
newWhoisAction("nameserver 1.2.3.4").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).contains("ns1.cat.lol");
}
@Test
void testRun_ipMapsToMultipleNameservers_theyAllGetReturned() {
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4"));
persistResource(FullFieldsTestEntityHelper.makeHost("ns2.cat.lol", "1.2.3.4"));
newWhoisAction("nameserver 1.2.3.4").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).contains("ns1.cat.lol");
assertThat(response.getPayload()).contains("ns2.cat.lol");
}
@Test
void testRun_ipMapsToMultipleNameserverInDifferentTlds_showsThemAll() {
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4"));
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.xn--q9jyb4c", "1.2.3.4"));
newWhoisAction("nameserver 1.2.3.4").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).contains("ns1.cat.lol");
assertThat(response.getPayload()).contains("ns1.cat.xn--q9jyb4c");
}
@Test
void testRun_ipNameserverEntityDoesNotExist_returns200NotFound() {
newWhoisAction("nameserver feed:a:bee::acab\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_ip_not_found.txt"));
}
@Test
void testRun_ipMapsToNameserverUnderNonAuthoritativeTld_notFound() {
assertThat(getTlds()).doesNotContain("com");
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.google.com", "1.2.3.4"));
newWhoisAction("nameserver 1.2.3.4").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_ip_not_found.txt"));
}
@Test
void testRun_nameserverUnderNonAuthoritativeTld_notFound() {
assertThat(getTlds()).doesNotContain("com");
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.google.com", "1.2.3.4"));
newWhoisAction("nameserver ns1.google.com").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_nameserver_not_found.txt"));
}
// todo (b/27378695): reenable or delete this test
@Disabled
@Test
void testRun_nameserverInTestTld_notFound() {
persistResource(Tld.get("lol").asBuilder().setTldType(Tld.TldType.TEST).build());
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4"));
newWhoisAction("nameserver ns1.cat.lol").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_nameserver_not_found.txt"));
}
@Test
void testRun_registrarLookup_works() {
Registrar registrar = persistResource(
makeRegistrar("example", "Example Registrar, Inc.", ACTIVE));
persistResources(makeRegistrarPocs(registrar));
// Notice the partial search without "inc".
newWhoisAction("registrar example registrar").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_registrar.txt"));
}
@Test
void testRun_pdtRegistrarLookup_works() {
Registrar registrar =
persistResource(
makeRegistrar("example", "Example Registrar, Inc.", ACTIVE)
.asBuilder()
.setIanaIdentifier(9995L)
.setType(PDT)
.build());
persistResources(makeRegistrarPocs(registrar));
// Notice the partial search without "inc".
newWhoisAction("registrar example registrar").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_registrar.txt"));
}
@Test
void testRun_registrarLookupInPendingState_returnsNotFound() {
Registrar registrar = persistResource(
makeRegistrar("example", "Example Registrar, Inc.", Registrar.State.PENDING));
persistResources(makeRegistrarPocs(registrar));
newWhoisAction("registrar Example Registrar, Inc.").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_registrar_not_found.txt"));
}
@Test
void testRun_registrarLookupWithTestType_returnsNotFound() {
Registrar registrar = persistResource(
makeRegistrar("example", "Example Registrar, Inc.", ACTIVE)
.asBuilder()
.setIanaIdentifier(null)
.setType(Registrar.Type.TEST)
.build());
persistResources(makeRegistrarPocs(registrar));
newWhoisAction("registrar Example Registrar, Inc.").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_registrar_not_found.txt"));
}
@Test
void testRun_multilevelDomain_isNotConsideredAHostname() {
Registrar registrar =
persistResource(makeRegistrar("example", "Example Registrar", ACTIVE));
persistResource(
makeDomain(
"cat.1.test",
persistResource(
FullFieldsTestEntityHelper.makeContact("5372808-ERL", "(◕‿◕)", "lol@cat.1.test")),
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-IRL", "Santa Claus", "BOFH@cat.1.test")),
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-TRL", "The Raven", "bog@cat.1.test")),
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.1.test", "1.2.3.4")),
persistResource(
FullFieldsTestEntityHelper.makeHost("ns2.cat.1.test", "bad:f00d:cafe::15:beef")),
registrar));
persistResources(makeRegistrarPocs(registrar));
newWhoisAction("domain cat.1.test\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).contains("Domain Name: cat.1.test\r\n");
}
@Test
void testRun_hostnameWithMultilevelTld_isStillConsideredHostname() {
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.1.test", "1.2.3.4"));
newWhoisAction("nameserver ns1.cat.1.test\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).contains("ns1.cat.1.test");
assertThat(response.getPayload()).contains("1.2.3.4");
}
@Test
void testRun_metricsLoggedForSuccessfulCommand() {
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4"));
persistResource(FullFieldsTestEntityHelper.makeHost("ns2.cat.lol", "1.2.3.4"));
WhoisAction action = newWhoisAction("nameserver 1.2.3.4");
action.whoisMetrics = mock(WhoisMetrics.class);
action.run();
WhoisMetric expected =
WhoisMetric.builderForRequest(clock)
.setCommandName("NameserverLookupByIp")
.setNumResults(2)
.setStatus(SC_OK)
.build();
verify(action.whoisMetrics).recordWhoisMetric(eq(expected));
}
@Test
void testRun_metricsLoggedForUnsuccessfulCommand() {
WhoisAction action = newWhoisAction("domain cat.lol\r\n");
action.whoisMetrics = mock(WhoisMetrics.class);
action.run();
WhoisMetric expected =
WhoisMetric.builderForRequest(clock)
.setCommandName("DomainLookup")
.setNumResults(0)
.setStatus(SC_NOT_FOUND)
.build();
verify(action.whoisMetrics).recordWhoisMetric(eq(expected));
}
@Test
void testRun_metricsLoggedForInternalServerError() throws Exception {
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4"));
WhoisAction action = newWhoisAction("ns1.cat.lol");
action.whoisReader = mock(WhoisReader.class);
when(action.whoisReader.readCommand(any(Reader.class), eq(false), any(DateTime.class)))
.thenThrow(new IOException("missing cat interface"));
action.whoisMetrics = mock(WhoisMetrics.class);
action.run();
WhoisMetric expected =
WhoisMetric.builderForRequest(clock)
.setNumResults(0)
.setStatus(SC_INTERNAL_SERVER_ERROR)
.build();
verify(action.whoisMetrics).recordWhoisMetric(eq(expected));
assertThat(response.getPayload()).isEqualTo("Internal Server Error");
}
}
@@ -1,244 +0,0 @@
// Copyright 2021 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.whois;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.testing.DatabaseHelper.newHost;
import static google.registry.testing.DatabaseHelper.newTld;
import static google.registry.testing.DatabaseHelper.persistNewRegistrar;
import static google.registry.testing.DatabaseHelper.persistResource;
import com.google.common.collect.ImmutableSet;
import com.google.common.net.InternetDomainName;
import google.registry.config.RegistryConfig;
import google.registry.model.domain.Domain;
import google.registry.model.host.Host;
import google.registry.model.registrar.Registrar;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeClock;
import google.registry.testing.TestCacheExtension;
import java.net.InetAddress;
import java.time.Duration;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
class WhoisCommandFactoryTest {
FakeClock clock = new FakeClock();
@RegisterExtension
final JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
@RegisterExtension
final TestCacheExtension testCacheExtension =
new TestCacheExtension.Builder().withEppResourceCache(Duration.ofSeconds(1000000)).build();
WhoisCommandFactory noncachedFactory = WhoisCommandFactory.createNonCached();
WhoisCommandFactory cachedFactory = WhoisCommandFactory.createCached();
Domain domain;
Host host;
Registrar otherRegistrar;
int origSingletonCacheRefreshSeconds;
@BeforeEach
void setUp() throws Exception {
persistResource(newTld("tld", "TLD"));
host =
newHost("ns.example.tld")
.asBuilder()
.setInetAddresses(ImmutableSet.of(InetAddress.getByName("1.2.3.4")))
.build();
persistResource(host);
domain = DatabaseHelper.newDomain("example.tld", host);
persistResource(domain);
otherRegistrar = persistNewRegistrar("OtherRegistrar");
otherRegistrar =
persistResource(
otherRegistrar
.asBuilder()
.setState(Registrar.State.ACTIVE)
.setPhoneNumber("+1.2223334444")
.build());
// In addition to the TestCacheExtension, we have to set a long singleton cache timeout.
RegistryConfig.CONFIG_SETTINGS.get().caching.singletonCacheRefreshSeconds = 1000000;
}
@AfterEach
void tearDown() {
// Restore the singleton cache timeout. For some reason, this doesn't work if we store the
// original value in an instance variable (I suspect there may be some overlap in test
// execution) so just restore to zero.
RegistryConfig.CONFIG_SETTINGS.get().caching.singletonCacheRefreshSeconds = 0;
}
@Test
void testNonCached_NameserverLookupByHostCommand() throws Exception {
WhoisResponse response =
noncachedFactory
.nameserverLookupByHost(InternetDomainName.from("ns.example.tld"))
.executeQuery(clock.nowUtc());
assertThat(response.getResponse(false, "").plainTextOutput())
.contains("Registrar: The Registrar");
// Note that we can't use persistResource() for these as that clears the cache.
tm().transact(
() ->
tm().put(
host.asBuilder()
.setPersistedCurrentSponsorRegistrarId("OtherRegistrar")
.build()));
response =
noncachedFactory
.nameserverLookupByHost(InternetDomainName.from("ns.example.tld"))
.executeQuery(clock.nowUtc());
assertThat(response.getResponse(false, "").plainTextOutput())
.contains("Registrar: OtherRegistrar name");
}
@Test
void testCached_NameserverLookupByHostCommand() throws Exception {
WhoisResponse response =
cachedFactory
.nameserverLookupByHost(InternetDomainName.from("ns.example.tld"))
.executeQuery(clock.nowUtc());
assertThat(response.getResponse(false, "").plainTextOutput())
.contains("Registrar: The Registrar");
tm().transact(
() ->
tm().put(
host.asBuilder()
.setPersistedCurrentSponsorRegistrarId("OtherRegistrar")
.build()));
response =
cachedFactory
.nameserverLookupByHost(InternetDomainName.from("ns.example.tld"))
.executeQuery(clock.nowUtc());
assertThat(response.getResponse(false, "").plainTextOutput())
.contains("Registrar: The Registrar");
}
@Test
void testNonCached_DomainLookupCommand() throws Exception {
WhoisResponse response =
noncachedFactory
.domainLookup(
InternetDomainName.from("example.tld"), true, "REDACTED", "Blocked by BSA")
.executeQuery(clock.nowUtc());
assertThat(response.getResponse(false, "").plainTextOutput())
.contains("Registrar: The Registrar");
tm().transact(
() ->
tm().put(
domain
.asBuilder()
.setPersistedCurrentSponsorRegistrarId("OtherRegistrar")
.build()));
response =
noncachedFactory
.domainLookup(
InternetDomainName.from("example.tld"), true, "REDACTED", "Blocked by BSA")
.executeQuery(clock.nowUtc());
assertThat(response.getResponse(false, "").plainTextOutput())
.contains("Registrar: OtherRegistrar name");
}
@Test
void testCached_DomainLookupCommand() throws Exception {
WhoisResponse response =
cachedFactory
.domainLookup(InternetDomainName.from("example.tld"), true, "REDACTED", "Not tested")
.executeQuery(clock.nowUtc());
assertThat(response.getResponse(false, "").plainTextOutput())
.contains("Registrar: The Registrar");
tm().transact(
() ->
tm().put(
domain
.asBuilder()
.setPersistedCurrentSponsorRegistrarId("OtherRegistrar")
.build()));
response =
cachedFactory
.domainLookup(
InternetDomainName.from("example.tld"), true, "REDACTED", "Blocked by BSA")
.executeQuery(clock.nowUtc());
assertThat(response.getResponse(false, "").plainTextOutput())
.contains("Registrar: The Registrar");
}
@Test
void testNonCached_RegistrarLookupCommand() throws Exception {
WhoisResponse response =
noncachedFactory.registrarLookup("OtherRegistrar").executeQuery(clock.nowUtc());
assertThat(response.getResponse(false, "").plainTextOutput())
.contains("Phone Number: +1.2223334444");
tm().transact(
() -> tm().put(otherRegistrar.asBuilder().setPhoneNumber("+1.2345677890").build()));
response = noncachedFactory.registrarLookup("OtherRegistrar").executeQuery(clock.nowUtc());
assertThat(response.getResponse(false, "").plainTextOutput())
.contains("Phone Number: +1.2345677890");
}
@Test
void testCached_RegistrarLookupCommand() throws Exception {
WhoisResponse response =
cachedFactory.registrarLookup("OtherRegistrar").executeQuery(clock.nowUtc());
assertThat(response.getResponse(false, "").plainTextOutput())
.contains("Phone Number: +1.2223334444");
tm().transact(
() -> tm().put(otherRegistrar.asBuilder().setPhoneNumber("+1.2345677890").build()));
response = cachedFactory.registrarLookup("OtherRegistrar").executeQuery(clock.nowUtc());
assertThat(response.getResponse(false, "").plainTextOutput())
.contains("Phone Number: +1.2223334444");
}
@Test
void testNonCached_NameserverLookupByIpCommand() throws Exception {
// Note that this lookup currently doesn't cache the hosts, so there's no point in testing the
// "cached" case. This test is here so that it will fail if anyone adds caching.
WhoisResponse response =
noncachedFactory
.nameserverLookupByIp(InetAddress.getByName("1.2.3.4"))
.executeQuery(clock.nowUtc());
assertThat(response.getResponse(false, "").plainTextOutput())
.contains("Registrar: The Registrar");
tm().transact(
() ->
tm().put(
host.asBuilder()
.setPersistedCurrentSponsorRegistrarId("OtherRegistrar")
.build()));
response =
noncachedFactory
.nameserverLookupByIp(InetAddress.getByName("1.2.3.4"))
.executeQuery(clock.nowUtc());
assertThat(response.getResponse(false, "").plainTextOutput())
.contains("Registrar: OtherRegistrar");
}
}
@@ -1,466 +0,0 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.whois;
import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.bsa.persistence.BsaTestingUtils.persistBsaLabel;
import static google.registry.model.registrar.Registrar.State.ACTIVE;
import static google.registry.testing.DatabaseHelper.createTlds;
import static google.registry.testing.DatabaseHelper.loadRegistrar;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.testing.DatabaseHelper.persistResources;
import static google.registry.testing.FullFieldsTestEntityHelper.makeDomain;
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrar;
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrarPocs;
import static google.registry.whois.WhoisTestData.loadFile;
import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
import static jakarta.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import google.registry.model.contact.Contact;
import google.registry.model.registrar.Registrar;
import google.registry.model.tld.Tld;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import google.registry.testing.FullFieldsTestEntityHelper;
import google.registry.whois.WhoisMetrics.WhoisMetric;
import java.io.IOException;
import java.io.Reader;
import java.util.Optional;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/**
* Unit tests for {@link WhoisHttpAction}.
*
* <p>This class should be limited to testing the HTTP interface, as the bulk of the WHOIS testing
* can be found in {@link WhoisActionTest}.
*/
class WhoisHttpActionTest {
@RegisterExtension
final JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
private final FakeResponse response = new FakeResponse();
private final FakeClock clock = new FakeClock(DateTime.parse("2009-06-29T20:13:00Z"));
private WhoisHttpAction newWhoisHttpAction(String pathInfo) {
WhoisHttpAction whoisAction = new WhoisHttpAction();
whoisAction.clock = clock;
whoisAction.expires = Duration.standardHours(1);
whoisAction.requestPath = WhoisHttpAction.PATH + pathInfo;
whoisAction.response = response;
whoisAction.whoisReader =
new WhoisReader(
WhoisCommandFactory.createCached(), "Please contact registrar", "Blocked by BSA: %s");
whoisAction.whoisMetrics = new WhoisMetrics();
whoisAction.metricBuilder = WhoisMetric.builderForRequest(clock);
whoisAction.disclaimer =
"Doodle Disclaimer\nI exist so that carriage return\nin disclaimer can be tested.";
return whoisAction;
}
@BeforeEach
void beforeEach() {
createTlds("lol", "xn--q9jyb4c", "1.test");
}
@Test
void testRun_emptyQuery_returns400BadRequestWithPlainTextOutput() {
newWhoisHttpAction("").run();
assertThat(response.getStatus()).isEqualTo(400);
assertThat(response.getContentType()).isEqualTo(PLAIN_TEXT_UTF_8);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_no_command.txt"));
}
@Test
void testRun_badUrlEncoding_returns400BadRequestWithPlainTextOutput() {
newWhoisHttpAction("nic.%u307F%u3093%u306A").run();
assertThat(response.getStatus()).isEqualTo(400);
assertThat(response.getContentType()).isEqualTo(PLAIN_TEXT_UTF_8);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_malformed_path.txt"));
}
@Test
void testRun_domainNotFound_returns404StatusAndPlainTextResponse() {
newWhoisHttpAction("/domain/cat.lol").run();
assertThat(response.getStatus()).isEqualTo(404);
assertThat(response.getContentType()).isEqualTo(PLAIN_TEXT_UTF_8);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_domain_not_found.txt"));
}
// todo (b/27378695): reenable or delete this test
@Disabled
@Test
void testRun_domainInTestTld_isConsideredNotFound() {
persistResource(Tld.get("lol").asBuilder().setTldType(Tld.TldType.TEST).build());
Registrar registrar = persistResource(makeRegistrar(
"evilregistrar", "Yes Virginia", Registrar.State.ACTIVE));
persistResource(
makeDomain(
"cat.lol",
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-ERL", "Goblin Market", "lol@cat.lol")),
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-IRL", "Santa Claus", "BOFH@cat.lol")),
persistResource(
FullFieldsTestEntityHelper.makeContact("5372808-TRL", "The Raven", "bog@cat.lol")),
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4")),
persistResource(
FullFieldsTestEntityHelper.makeHost("ns2.cat.lol", "bad:f00d:cafe::15:beef")),
registrar));
persistResources(makeRegistrarPocs(registrar));
newWhoisHttpAction("/domain/cat.lol").run();
assertThat(response.getStatus()).isEqualTo(404);
assertThat(response.getContentType()).isEqualTo(PLAIN_TEXT_UTF_8);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_domain_not_found.txt"));
}
@Test
void testRun_domainQueryIdn_works() {
Registrar registrar = persistResource(makeRegistrar(
"evilregistrar", "Yes Virginia", Registrar.State.ACTIVE));
persistResource(
makeDomain(
"cat.みんな",
persistResource(
FullFieldsTestEntityHelper.makeContact("5372808-ERL", "(◕‿◕)", "lol@cat.みんな")),
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-IRL", "Santa Claus", "BOFH@cat.みんな")),
persistResource(
FullFieldsTestEntityHelper.makeContact("5372808-TRL", "The Raven", "bog@cat.みんな")),
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.みんな", "1.2.3.4")),
persistResource(
FullFieldsTestEntityHelper.makeHost("ns2.cat.みんな", "bad:f00d:cafe::15:beef")),
registrar));
persistResources(makeRegistrarPocs(registrar));
newWhoisHttpAction("/domain/cat.みんな").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_idn_utf8.txt"));
}
@Test
void testRun_wickedLineFeedForgeryInDatabase_crlfSubstitutedWithSpace() {
Contact trl =
FullFieldsTestEntityHelper.makeContact("5372808-TRL", "Eric Schmidt", "bog@cat.みんな");
trl =
persistResource(
trl.asBuilder()
.setInternationalizedPostalInfo(
trl.getInternationalizedPostalInfo()
.asBuilder()
.setOrg("Galactic\r\nEmpire")
.build())
.build());
persistResource(
makeDomain(
"cat.みんな",
trl,
trl,
trl,
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.みんな", "1.2.3.4")),
persistResource(
FullFieldsTestEntityHelper.makeHost("ns2.cat.みんな", "bad:f00d:cafe::15:beef")),
persistResource(
makeRegistrar("example", "Example Registrar", Registrar.State.ACTIVE))));
newWhoisHttpAction("/domain/cat.みんな").run();
assertThat(response.getPayload()).contains("Galactic Empire");
}
@Test
void testRun_domainOnly_works() {
persistResource(
makeDomain(
"cat.みんな",
persistResource(
FullFieldsTestEntityHelper.makeContact("5372808-ERL", "(◕‿◕)", "lol@cat.みんな")),
persistResource(
FullFieldsTestEntityHelper.makeContact("5372808-IRL", "Operator", "BOFH@cat.みんな")),
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-TRL", "Eric Schmidt", "bog@cat.みんな")),
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.みんな", "1.2.3.4")),
persistResource(
FullFieldsTestEntityHelper.makeHost("ns2.cat.みんな", "bad:f00d:cafe::15:beef")),
persistResource(
makeRegistrar("example", "Example Registrar", Registrar.State.ACTIVE))));
newWhoisHttpAction("cat.みんな").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).contains("Domain Name: cat.みんな\r\n");
}
@Test
void testRun_domainQuery_registeredDomainUnaffectedByBsa() {
persistResource(
Tld.get("lol")
.asBuilder()
.setBsaEnrollStartTime(Optional.of(clock.nowUtc().minusDays(1)))
.build());
persistBsaLabel("cat");
Registrar registrar = persistResource(makeRegistrar("evilregistrar", "Yes Virginia", ACTIVE));
persistResource(
makeDomain(
"cat.lol",
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-ERL", "Goblin Market", "lol@cat.lol")),
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-IRL", "Santa Claus", "BOFH@cat.lol")),
persistResource(
FullFieldsTestEntityHelper.makeContact("5372808-TRL", "The Raven", "bog@cat.lol")),
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4")),
persistResource(
FullFieldsTestEntityHelper.makeHost("ns2.cat.lol", "bad:f00d:cafe::15:beef")),
registrar));
persistResources(makeRegistrarPocs(registrar));
newWhoisHttpAction("domain cat.lol\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_domain.txt"));
}
@Test
void testRun_domainQuery_unregisteredDomainShowBsaMessage() {
persistResource(
Tld.get("lol")
.asBuilder()
.setBsaEnrollStartTime(Optional.of(clock.nowUtc().minusDays(1)))
.build());
persistBsaLabel("cat");
newWhoisHttpAction("domain cat.lol\r\n").run();
assertThat(response.getStatus()).isEqualTo(404);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_domain_blocked_by_bsa.txt"));
}
@Test
void testRun_hostnameOnly_works() {
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.みんな", "1.2.3.4"));
newWhoisHttpAction("ns1.cat.みんな").run();
assertThat(response.getPayload()).contains("Server Name: ns1.cat.みんな\r\n");
}
@Test
void testRun_domainQueryPunycode_works() {
Registrar registrar = persistResource(makeRegistrar(
"evilregistrar", "Yes Virginia", Registrar.State.ACTIVE));
persistResource(
makeDomain(
"cat.みんな",
persistResource(
FullFieldsTestEntityHelper.makeContact("5372808-ERL", "(◕‿◕)", "lol@cat.みんな")),
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-IRL", "Santa Claus", "BOFH@cat.みんな")),
persistResource(
FullFieldsTestEntityHelper.makeContact("5372808-TRL", "The Raven", "bog@cat.みんな")),
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.みんな", "1.2.3.4")),
persistResource(
FullFieldsTestEntityHelper.makeHost("ns2.cat.みんな", "bad:f00d:cafe::15:beef")),
registrar));
persistResources(makeRegistrarPocs(registrar));
newWhoisHttpAction("/domain/cat.xn--q9jyb4c").run();
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_idn_utf8.txt"));
}
@Test
void testRun_nameserverQuery_works() {
persistResource(loadRegistrar("TheRegistrar").asBuilder().setUrl("http://my.fake.url").build());
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4"));
newWhoisHttpAction("/nameserver/ns1.cat.lol").run();
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_nameserver.txt"));
}
// todo (b/27378695): reenable or delete this test
@Disabled
@Test
void testRun_nameserverQueryInTestTld_notFound() {
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4"));
newWhoisHttpAction("/nameserver/ns1.cat.lol").run();
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_nameserver.txt"));
}
@Test
void testRun_lastUpdateTimestamp_isPresentInResponse() {
clock.setTo(DateTime.parse("2020-07-12T23:52:43Z"));
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4"));
newWhoisHttpAction("/nameserver/ns1.cat.lol").run();
assertThat(response.getPayload())
.contains(">>> Last update of WHOIS database: 2020-07-12T23:52:43Z <<<");
}
@Test
void testRun_nameserverQueryIdn_works() {
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.みんな", "1.2.3.4"));
newWhoisHttpAction("/nameserver/ns1.cat.みんな").run();
assertThat(response.getPayload()).contains("ns1.cat.みんな");
assertThat(response.getPayload()).contains("1.2.3.4");
}
@Test
void testRun_nameserverQueryPunycode_works() {
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.みんな", "1.2.3.4"));
newWhoisHttpAction("/nameserver/ns1.cat.xn--q9jyb4c").run();
assertThat(response.getPayload()).contains("ns1.cat.みんな");
assertThat(response.getPayload()).contains("1.2.3.4");
}
@Test
void testRun_trailingSlashInPath_getsIgnored() {
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.みんな", "1.2.3.4"));
newWhoisHttpAction("/nameserver/ns1.cat.xn--q9jyb4c/").run();
assertThat(response.getPayload()).contains("ns1.cat.みんな");
assertThat(response.getPayload()).contains("1.2.3.4");
}
@Test
void testRun_uppercaseDomain_ignoresCasing() {
persistResource(
makeDomain(
"cat.lol",
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-ERL", "Peter Murphy", "lol@cat.lol")),
persistResource(
FullFieldsTestEntityHelper.makeContact("5372808-IRL", "Operator", "BOFH@cat.lol")),
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-TRL", "Eric Schmidt", "bog@cat.lol")),
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4")),
persistResource(
FullFieldsTestEntityHelper.makeHost("ns2.cat.lol", "bad:f00d:cafe::15:beef")),
persistResource(
makeRegistrar("example", "Example Registrar", Registrar.State.ACTIVE))));
newWhoisHttpAction("/domain/cat.LOL").run();
assertThat(response.getPayload()).contains("Domain Name: cat.lol\r\n");
}
@Test
void testRun_hairyPath_getsDecoded() {
persistResource(
makeDomain(
"cat.lol",
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-ERL", "Peter Murphy", "lol@cat.lol")),
persistResource(
FullFieldsTestEntityHelper.makeContact("5372808-IRL", "Operator", "BOFH@cat.lol")),
persistResource(
FullFieldsTestEntityHelper.makeContact(
"5372808-TRL", "Eric Schmidt", "bog@cat.lol")),
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4")),
persistResource(
FullFieldsTestEntityHelper.makeHost("ns2.cat.lol", "bad:f00d:cafe::15:beef")),
persistResource(
makeRegistrar("example", "Example Registrar", Registrar.State.ACTIVE))));
// python -c "print ''.join('%' + hex(ord(c))[2:] for c in 'cat.lol')"
newWhoisHttpAction("/domain/%63%61%74%2e%6c%6f%6c").run();
assertThat(response.getPayload()).contains("Domain Name: cat.lol\r\n");
}
@Test
void testRun_registrarLookup_works() {
Registrar registrar = persistResource(
makeRegistrar("example", "Example Registrar, Inc.", Registrar.State.ACTIVE));
persistResources(makeRegistrarPocs(registrar));
// Notice the partial search without "inc".
newWhoisHttpAction("/registrar/Example%20Registrar").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_registrar.txt"));
}
@Test
void testRun_registrarLookupInPendingState_returnsNotFound() {
Registrar registrar = persistResource(
makeRegistrar("example", "Example Registrar, Inc.", Registrar.State.PENDING));
persistResources(makeRegistrarPocs(registrar));
newWhoisHttpAction("/registrar/Example%20Registrar,%20Inc.").run();
assertThat(response.getStatus()).isEqualTo(404);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_registrar_not_found.txt"));
}
@Test
void testRun_registrarLookupWithTestType_returnsNotFound() {
Registrar registrar = persistResource(
makeRegistrar("example", "Example Registrar, Inc.", Registrar.State.ACTIVE)
.asBuilder().setType(Registrar.Type.TEST).setIanaIdentifier(null).build());
persistResources(makeRegistrarPocs(registrar));
newWhoisHttpAction("/registrar/Example%20Registrar,%20Inc.").run();
assertThat(response.getStatus()).isEqualTo(404);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_registrar_not_found.txt"));
}
@Test
void testRun_metricsLoggedForSuccessfulCommand() {
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4"));
WhoisHttpAction action = newWhoisHttpAction("/nameserver/ns1.cat.lol");
action.whoisMetrics = mock(WhoisMetrics.class);
action.run();
WhoisMetric expected =
WhoisMetric.builderForRequest(clock)
.setCommandName("NameserverLookupByHost")
.setNumResults(1)
.setStatus(SC_OK)
.build();
verify(action.whoisMetrics).recordWhoisMetric(eq(expected));
}
@Test
void testRun_metricsLoggedForUnsuccessfulCommand() {
WhoisHttpAction action = newWhoisHttpAction("nic.%u307F%u3093%u306A");
action.whoisMetrics = mock(WhoisMetrics.class);
action.run();
WhoisMetric expected =
WhoisMetric.builderForRequest(clock).setNumResults(0).setStatus(SC_BAD_REQUEST).build();
verify(action.whoisMetrics).recordWhoisMetric(eq(expected));
}
@Test
void testRun_metricsLoggedForInternalServerError() throws Exception {
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4"));
WhoisHttpAction action = newWhoisHttpAction("ns1.cat.lol");
action.whoisReader = mock(WhoisReader.class);
when(action.whoisReader.readCommand(any(Reader.class), eq(false), any(DateTime.class)))
.thenThrow(new IOException("missing cat interface"));
action.whoisMetrics = mock(WhoisMetrics.class);
RuntimeException thrown = assertThrows(RuntimeException.class, action::run);
assertThat(thrown).hasCauseThat().hasMessageThat().isEqualTo("missing cat interface");
WhoisMetric expected =
WhoisMetric.builderForRequest(clock)
.setNumResults(0)
.setStatus(SC_INTERNAL_SERVER_ERROR)
.build();
verify(action.whoisMetrics).recordWhoisMetric(eq(expected));
}
}
@@ -1,81 +0,0 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.whois;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.persistResource;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.request.RequestModule;
import google.registry.testing.FullFieldsTestEntityHelper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for Dagger injection of the whois package. */
final class WhoisInjectionTest {
@RegisterExtension
final JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
private final HttpServletRequest req = mock(HttpServletRequest.class);
private final HttpServletResponse rsp = mock(HttpServletResponse.class);
private final StringWriter httpOutput = new StringWriter();
@BeforeEach
void beforeEach() throws Exception {
when(rsp.getWriter()).thenReturn(new PrintWriter(httpOutput));
}
@Test
void testWhoisAction_injectsAndWorks() throws Exception {
createTld("lol");
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4"));
when(req.getReader()).thenReturn(new BufferedReader(new StringReader("ns1.cat.lol\r\n")));
DaggerWhoisTestComponent.builder()
.requestModule(new RequestModule(req, rsp))
.build()
.whoisAction()
.run();
verify(rsp).setStatus(200);
assertThat(httpOutput.toString()).contains("ns1.cat.lol");
}
@Test
void testWhoisHttpAction_injectsAndWorks() {
createTld("lol");
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4"));
when(req.getRequestURI()).thenReturn("/whois/ns1.cat.lol");
DaggerWhoisTestComponent.builder()
.requestModule(new RequestModule(req, rsp))
.build()
.whoisHttpAction()
.run();
verify(rsp).setStatus(200);
assertThat(httpOutput.toString()).contains("ns1.cat.lol");
}
}
@@ -1,423 +0,0 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.whois;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatabaseHelper.createTlds;
import static google.registry.testing.LogsSubject.assertAboutLogs;
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.google.common.testing.TestLogHandler;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.testing.FakeClock;
import google.registry.util.JdkLoggerConfig;
import java.io.StringReader;
import java.util.logging.Level;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link WhoisReader}. */
class WhoisReaderTest {
@RegisterExtension
final JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
private final FakeClock clock = new FakeClock();
private final TestLogHandler testLogHandler = new TestLogHandler();
@BeforeEach
void beforeEach() {
createTlds("tld", "xn--kgbechtv", "1.test");
JdkLoggerConfig.getConfig(WhoisReader.class).addHandler(testLogHandler);
}
@SuppressWarnings({"TypeParameterUnusedInFormals", "unchecked"})
<T> T readCommand(String commandStr) throws Exception {
return (T)
new WhoisReader(
WhoisCommandFactory.createCached(), "Please contact registrar", "Blocked by BSA")
.readCommand(new StringReader(commandStr), false, clock.nowUtc());
}
void assertLoadsExampleTld(String commandString) throws Exception {
DomainLookupCommand command = readCommand(commandString);
assertThat(command.domainName.toString()).isEqualTo("example.tld");
}
void assertLoadsIDN(String commandString) throws Exception {
DomainLookupCommand command = readCommand(commandString);
assertThat(command.domainName.toString()).isEqualTo("xn--mgbh0fb.xn--kgbechtv");
}
void assertLoadsExampleNs(String commandString) throws Exception {
NameserverLookupByHostCommand command = readCommand(commandString);
assertThat(command.hostName.toString()).isEqualTo("ns.example.tld");
}
void assertLoadsIDNNs(String commandString) throws Exception {
NameserverLookupByHostCommand command = readCommand(commandString);
assertThat(command.hostName.toString()).isEqualTo("ns.xn--mgbh0fb.xn--kgbechtv");
}
void assertNsLookup(String commandString, String expectedIpAddress) throws Exception {
assertThat(
this.<NameserverLookupByIpCommand>readCommand(commandString).ipAddress.getHostAddress())
.isEqualTo(expectedIpAddress);
}
void assertLoadsRegistrar(String commandString) throws Exception {
assertThat(this.<RegistrarLookupCommand>readCommand(commandString).registrarName)
.isEqualTo("Example Registrar, Inc.");
}
@Test
void testRegistrarLookupWithOneToken() throws Exception {
assertThat(this.<RegistrarLookupCommand>readCommand("Example").registrarName)
.isEqualTo("Example");
}
@Test
void testDomainLookupWithoutCRLF() throws Exception {
assertLoadsExampleTld("example.tld");
}
@Test
void testWhitespaceOnDomainLookupWithCommand() throws Exception {
assertLoadsExampleTld(" \t domain \t \t example.tld \r\n");
}
@Test
void testDomainLookup() throws Exception {
assertLoadsExampleTld("example.tld\r\n");
}
@Test
void testDomainLookupWithCommand() throws Exception {
assertLoadsExampleTld("domain example.tld\r\n");
}
@Test
void testCaseInsensitiveDomainLookup() throws Exception {
assertLoadsExampleTld("EXAMPLE.TLD\r\n");
}
@Test
void testCaseInsensitiveDomainLookupWithCommand() throws Exception {
assertLoadsExampleTld("DOMAIN EXAMPLE.TLD\r\n");
}
@Test
void testIDNULabelDomainLookup() throws Exception {
assertLoadsIDN("مثال.إختبار\r\n");
}
@Test
void testIDNULabelDomainLookupWithCommand() throws Exception {
assertLoadsIDN("domain مثال.إختبار\r\n");
}
@Test
void testIDNALabelDomainLookupWithCommand() throws Exception {
assertLoadsIDN("domain xn--mgbh0fb.xn--kgbechtv\r\n");
}
@Test
void testIDNALabelDomainLookup() throws Exception {
assertLoadsIDN("xn--mgbh0fb.xn--kgbechtv\r\n");
}
@Test
void testTooManyArgsDomainLookup() {
assertThrows(WhoisException.class, () -> readCommand("domain example.tld foo.bar"));
}
@Test
void testTooFewArgsDomainLookup() {
assertThrows(WhoisException.class, () -> readCommand("domain"));
}
@Test
void testIllegalArgDomainLookup() {
assertThrows(WhoisException.class, () -> readCommand("domain 1.1"));
}
@Test
void testNameserverLookupWithoutCRLF() throws Exception {
assertLoadsExampleNs("ns.example.tld");
}
@Test
void testWhitespaceOnNameserverLookupWithCommand() throws Exception {
assertLoadsExampleNs(" \t nameserver \t \t ns.example.tld \r\n");
}
@Test
void testNameserverLookup() throws Exception {
assertLoadsExampleNs("ns.example.tld\r\n");
}
@Test
void testDeepNameserverLookup() throws Exception {
NameserverLookupByHostCommand command = readCommand("ns.foo.bar.baz.example.tld\r\n");
assertThat(command.hostName.toString()).isEqualTo("ns.foo.bar.baz.example.tld");
assertThat(command.hostName.toString()).isEqualTo("ns.foo.bar.baz.example.tld");
}
@Test
void testNameserverLookupWithCommand() throws Exception {
assertLoadsExampleNs("nameserver ns.example.tld\r\n");
}
@Test
void testCaseInsensitiveNameserverLookup() throws Exception {
assertLoadsExampleNs("NS.EXAMPLE.TLD\r\n");
}
@Test
void testCaseInsensitiveNameserverLookupWithCommand() throws Exception {
assertLoadsExampleNs("NAMESERVER NS.EXAMPLE.TLD\r\n");
}
@Test
void testIDNULabelNameserverLookup() throws Exception {
assertLoadsIDNNs("ns.مثال.إختبار\r\n");
}
@Test
void testIDNULabelNameserverLookupWithCommand() throws Exception {
assertLoadsIDNNs("nameserver ns.مثال.إختبار\r\n");
}
@Test
void testIDNALabelNameserverLookupWithCommand() throws Exception {
assertLoadsIDNNs("nameserver ns.xn--mgbh0fb.xn--kgbechtv\r\n");
}
@Test
void testIDNALabelNameserverLookup() throws Exception {
assertLoadsIDNNs("ns.xn--mgbh0fb.xn--kgbechtv\r\n");
}
@Test
void testTooManyArgsNameserverLookup() {
assertThrows(WhoisException.class, () -> readCommand("nameserver ns.example.tld foo.bar"));
}
@Test
void testTooFewArgsNameserverLookup() {
assertThrows(WhoisException.class, () -> readCommand("nameserver"));
}
@Test
void testIllegalArgNameserverLookup() {
assertThrows(WhoisException.class, () -> readCommand("nameserver 1.1"));
}
@Test
void testRegistrarLookup() throws Exception {
assertLoadsRegistrar("registrar Example Registrar, Inc.");
}
@Test
void testRegistrarLookupCaseInsensitive() throws Exception {
assertLoadsRegistrar("REGISTRAR Example Registrar, Inc.");
}
@Test
void testRegistrarLookupWhitespace() throws Exception {
assertLoadsRegistrar(" \t registrar \t \tExample Registrar, Inc. ");
}
@Test
void testRegistrarLookupByDefault() throws Exception {
assertLoadsRegistrar("Example Registrar, Inc.");
}
@Test
void testRegistrarLookupOnTLD() throws Exception {
assertThat(this.<RegistrarLookupCommand>readCommand("com").registrarName).isEqualTo("com");
}
@Test
void testRegistrarLookupNoArgs() {
assertThrows(WhoisException.class, () -> readCommand("registrar"));
}
@Test
void testNameserverLookupByIp() throws Exception {
assertNsLookup("43.34.12.213", "43.34.12.213");
}
@Test
void testNameserverLookupByIpv6() throws Exception {
assertNsLookup("1080:0:0:0:8:800:200c:417a", "1080:0:0:0:8:800:200c:417a");
}
@Test
void testNameserverLookupByCompressedIpv6() throws Exception {
assertNsLookup("1080::8:800:200c:417a", "1080:0:0:0:8:800:200c:417a");
}
@Test
void testNameserverLookupByNoncanonicalIpv6() throws Exception {
assertNsLookup("1080:0:0:0:8:800:200C:417A", "1080:0:0:0:8:800:200c:417a");
}
@Test
void testNameserverLookupByBackwardsCompatibleIpv6() throws Exception {
assertNsLookup("::FFFF:129.144.52.38", "129.144.52.38");
}
@Test
void testNameserverLookupByIpWithCommand() throws Exception {
assertNsLookup("nameserver 43.34.12.213", "43.34.12.213");
}
@Test
void testNameserverLookupByIpv6WithCommand() throws Exception {
assertNsLookup("nameserver 1080:0:0:0:8:800:200C:417a", "1080:0:0:0:8:800:200c:417a");
}
@Test
void testNameserverLookupByIpCaseInsenstive() throws Exception {
assertNsLookup("NAMESERVER 43.34.12.213", "43.34.12.213");
}
@Test
void testNameserverLookupByIpWhitespace() throws Exception {
assertNsLookup(" \t\t NAMESERVER \t 43.34.12.213 \r\n", "43.34.12.213");
}
@Test
void testNameserverLookupByIpTooManyArgs() {
assertThrows(WhoisException.class, () -> readCommand("nameserver 43.34.12.213 43.34.12.213"));
}
@Test
void testMultilevelDomainLookup() throws Exception {
this.<DomainLookupCommand>readCommand("example.1.test");
}
@Test
void testMultilevelNameserverLookup() throws Exception {
this.<NameserverLookupByHostCommand>readCommand("ns.example.1.test");
}
@Test
void testDeepMultilevelNameserverLookup() throws Exception {
this.<NameserverLookupByHostCommand>readCommand("ns.corp.example.1.test");
}
@Test
void testUnconfiguredTld() throws Exception {
this.<RegistrarLookupCommand>readCommand("example.test");
this.<RegistrarLookupCommand>readCommand("1.example.test");
this.<RegistrarLookupCommand>readCommand("ns.example.2.test");
this.<RegistrarLookupCommand>readCommand("test");
this.<RegistrarLookupCommand>readCommand("tld");
}
@Test
void testNoArgs() {
assertThrows(WhoisException.class, () -> readCommand(""));
}
@Test
void testLogsDomainLookupCommand() throws Exception {
readCommand("domain example.tld");
assertAboutLogs()
.that(testLogHandler)
.hasLogAtLevelWithMessage(
Level.INFO, "Attempting domain lookup command using domain name 'example.tld'.");
}
@Test
void testLogsNameserverLookupCommandWithIpAddress() throws Exception {
readCommand("nameserver 43.34.12.213");
assertAboutLogs()
.that(testLogHandler)
.hasLogAtLevelWithMessage(
Level.INFO,
"Attempting nameserver lookup command using 43.34.12.213 as an IP address.");
}
@Test
void testLogsNameserverLookupCommandWithHostname() throws Exception {
readCommand("nameserver ns.example.tld");
assertAboutLogs()
.that(testLogHandler)
.hasLogAtLevelWithMessage(
Level.INFO, "Attempting nameserver lookup command using ns.example.tld as a hostname.");
}
@Test
void testLogsRegistrarLookupCommand() throws Exception {
readCommand("registrar Example Registrar, Inc.");
assertAboutLogs()
.that(testLogHandler)
.hasLogAtLevelWithMessage(
Level.INFO,
"Attempting registrar lookup command using registrar Example Registrar, Inc.");
}
@Test
void testLogsSingleArgumentNameserverLookupUsingIpAddress() throws Exception {
readCommand("43.34.12.213");
assertAboutLogs()
.that(testLogHandler)
.hasLogAtLevelWithMessage(
Level.INFO, "Attempting nameserver lookup using 43.34.12.213 as an IP address.");
}
@Test
void testLogsSingleArgumentRegistrarLookup() throws Exception {
readCommand("test");
assertAboutLogs()
.that(testLogHandler)
.hasLogAtLevelWithMessage(
Level.INFO, "Attempting registrar lookup using test as a registrar.");
}
@Test
void testLogsSingleArgumentDomainLookup() throws Exception {
readCommand("example.tld");
assertAboutLogs()
.that(testLogHandler)
.hasLogAtLevelWithMessage(
Level.INFO, "Attempting domain lookup using example.tld as a domain name.");
}
@Test
void testLogsSingleArgumentNameserverLookupUsingHostname() throws Exception {
readCommand("ns.example.tld");
assertAboutLogs()
.that(testLogHandler)
.hasLogAtLevelWithMessage(
Level.INFO, "Attempting nameserver lookup using ns.example.tld as a hostname.");
}
@Test
void testLogsMultipleArgumentsButNoParticularCommand() throws Exception {
readCommand("Example Registrar, Inc.");
assertAboutLogs()
.that(testLogHandler)
.hasLogAtLevelWithMessage(
Level.INFO,
"Attempting registrar lookup employing Example Registrar, Inc. as a registrar.");
}
}
@@ -1,35 +0,0 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.whois;
import dagger.Component;
import google.registry.config.RegistryConfig.ConfigModule;
import google.registry.request.RequestModule;
import google.registry.util.UtilsModule;
import jakarta.inject.Singleton;
@Singleton
@Component(
modules = {
ConfigModule.class,
RequestModule.class,
UtilsModule.class,
WhoisModule.class,
})
interface WhoisTestComponent {
WhoisHttpAction whoisHttpAction();
WhoisAction whoisAction();
}
@@ -1,29 +0,0 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.whois;
import google.registry.testing.TestDataHelper;
/** Test helper methods for the whois package. */
final class WhoisTestData {
/**
* Loads test data from file in {@code testdata/} directory, "fixing" newlines to have the ending
* that WHOIS requires.
*/
static String loadFile(String filename) {
return TestDataHelper.loadFile(WhoisTestData.class, filename).replaceAll("\r?\n", "\r\n");
}
}
@@ -1,5 +1,4 @@
SERVICE PATH CLASS METHODS OK MIN USER_POLICY
PUBAPI /_dr/whois WhoisAction POST n APP ADMIN
PUBAPI /check CheckApiAction GET n NONE PUBLIC
PUBAPI /rdap/ RdapEmptyAction GET,HEAD n NONE PUBLIC
PUBAPI /rdap/autnum/(*) RdapAutnumAction GET,HEAD n NONE PUBLIC
@@ -12,4 +11,3 @@ PUBAPI /rdap/ip/(*) RdapIpAction GET,HEAD n NONE PUBLIC
PUBAPI /rdap/nameserver/(*) RdapNameserverAction GET,HEAD n NONE PUBLIC
PUBAPI /rdap/nameservers RdapNameserverSearchAction GET,HEAD n NONE PUBLIC
PUBAPI /ready/pubapi ReadinessProbeActionPubApi GET n NONE PUBLIC
PUBAPI /whois/(*) WhoisHttpAction GET n NONE PUBLIC
@@ -56,7 +56,6 @@ BACKEND /_dr/task/tmchSmdrl TmchSmdrlAction
BACKEND /_dr/task/updateRegistrarRdapBaseUrls UpdateRegistrarRdapBaseUrlsAction GET y APP ADMIN
BACKEND /_dr/task/uploadBsaUnavailableNames UploadBsaUnavailableDomainsAction GET,POST n APP ADMIN
BACKEND /_dr/task/wipeOutContactHistoryPii WipeOutContactHistoryPiiAction GET n APP ADMIN
PUBAPI /_dr/whois WhoisAction POST n APP ADMIN
PUBAPI /check CheckApiAction GET n NONE PUBLIC
PUBAPI /rdap/ RdapEmptyAction GET,HEAD n NONE PUBLIC
PUBAPI /rdap/autnum/(*) RdapAutnumAction GET,HEAD n NONE PUBLIC
@@ -69,7 +68,6 @@ PUBAPI /rdap/ip/(*) RdapIpAction
PUBAPI /rdap/nameserver/(*) RdapNameserverAction GET,HEAD n NONE PUBLIC
PUBAPI /rdap/nameservers RdapNameserverSearchAction GET,HEAD n NONE PUBLIC
PUBAPI /ready/pubapi ReadinessProbeActionPubApi GET n NONE PUBLIC
PUBAPI /whois/(*) WhoisHttpAction GET n NONE PUBLIC
CONSOLE /console-api/bulk-domain ConsoleBulkDomainAction POST n USER PUBLIC
CONSOLE /console-api/domain ConsoleDomainGetAction GET n USER PUBLIC
CONSOLE /console-api/domain-list ConsoleDomainListAction GET n USER PUBLIC
@@ -1,59 +0,0 @@
Domain Name: cat.lol
Registry Domain ID: 9-LOL
Registrar WHOIS Server: whois.example.com
Registrar URL: http://my.fake.url
Updated Date: 2009-05-29T20:13:00Z
Creation Date: 2000-10-08T00:45:00Z
Registry Expiry Date: 2110-10-08T00:44:59Z
Registrar: Yes Virginia
Registrar IANA ID: 1
Registrar Abuse Contact Email: jakedoe@example.com
Registrar Abuse Contact Phone: +1.2125551216
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
Registry Registrant ID: REDACTED FOR PRIVACY
Registrant Name: REDACTED FOR PRIVACY
Registrant Organization: GOOGLE INCORPORATED <script>
Registrant Street: REDACTED FOR PRIVACY
Registrant City: REDACTED FOR PRIVACY
Registrant State/Province: BM
Registrant Postal Code: REDACTED FOR PRIVACY
Registrant Country: US
Registrant Phone: REDACTED FOR PRIVACY
Registrant Fax: REDACTED FOR PRIVACY
Registrant Email: Please contact registrar
Registry Admin ID: REDACTED FOR PRIVACY
Admin Name: REDACTED FOR PRIVACY
Admin Organization: REDACTED FOR PRIVACY
Admin Street: REDACTED FOR PRIVACY
Admin City: REDACTED FOR PRIVACY
Admin State/Province: REDACTED FOR PRIVACY
Admin Postal Code: REDACTED FOR PRIVACY
Admin Country: REDACTED FOR PRIVACY
Admin Phone: REDACTED FOR PRIVACY
Admin Fax: REDACTED FOR PRIVACY
Admin Email: Please contact registrar
Registry Tech ID: REDACTED FOR PRIVACY
Tech Name: REDACTED FOR PRIVACY
Tech Organization: REDACTED FOR PRIVACY
Tech Street: REDACTED FOR PRIVACY
Tech City: REDACTED FOR PRIVACY
Tech State/Province: REDACTED FOR PRIVACY
Tech Postal Code: REDACTED FOR PRIVACY
Tech Country: REDACTED FOR PRIVACY
Tech Phone: REDACTED FOR PRIVACY
Tech Fax: REDACTED FOR PRIVACY
Tech Email: Please contact registrar
Name Server: ns1.cat.lol
Name Server: ns2.cat.lol
DNSSEC: signedDelegation
URL of the ICANN Whois Inaccuracy Complaint Form: https://www.icann.org/wicf/
>>> Last update of WHOIS database: 2009-06-29T20:13: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.
@@ -1,6 +0,0 @@
Blocked by BSA: cat.lol
>>> Last update of WHOIS database: 2009-06-29T20:13:00Z <<<
Doodle Disclaimer
I exist so that carriage return
in disclaimer can be tested.
@@ -1,6 +0,0 @@
Domain not found.
>>> Last update of WHOIS database: 2009-06-29T20:13:00Z <<<
Doodle Disclaimer
I exist so that carriage return
in disclaimer can be tested.
@@ -1,59 +0,0 @@
Domain Name: cat.xn--q9jyb4c
Registry Domain ID: 9-Q9JYB4C
Registrar WHOIS Server: whois.example.com
Registrar URL: http://my.fake.url
Updated Date: 2009-05-29T20:13:00Z
Creation Date: 2000-10-08T00:45:00Z
Registry Expiry Date: 2110-10-08T00:44:59Z
Registrar: Yes Virginia
Registrar IANA ID: 1
Registrar Abuse Contact Email: jakedoe@example.com
Registrar Abuse Contact Phone: +1.2125551216
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
Registry Registrant ID: REDACTED FOR PRIVACY
Registrant Name: REDACTED FOR PRIVACY
Registrant Organization: GOOGLE INCORPORATED <script>
Registrant Street: REDACTED FOR PRIVACY
Registrant City: REDACTED FOR PRIVACY
Registrant State/Province: BM
Registrant Postal Code: REDACTED FOR PRIVACY
Registrant Country: US
Registrant Phone: REDACTED FOR PRIVACY
Registrant Fax: REDACTED FOR PRIVACY
Registrant Email: Please contact registrar
Registry Admin ID: REDACTED FOR PRIVACY
Admin Name: REDACTED FOR PRIVACY
Admin Organization: REDACTED FOR PRIVACY
Admin Street: REDACTED FOR PRIVACY
Admin City: REDACTED FOR PRIVACY
Admin State/Province: REDACTED FOR PRIVACY
Admin Postal Code: REDACTED FOR PRIVACY
Admin Country: REDACTED FOR PRIVACY
Admin Phone: REDACTED FOR PRIVACY
Admin Fax: REDACTED FOR PRIVACY
Admin Email: Please contact registrar
Registry Tech ID: REDACTED FOR PRIVACY
Tech Name: REDACTED FOR PRIVACY
Tech Organization: REDACTED FOR PRIVACY
Tech Street: REDACTED FOR PRIVACY
Tech City: REDACTED FOR PRIVACY
Tech State/Province: REDACTED FOR PRIVACY
Tech Postal Code: REDACTED FOR PRIVACY
Tech Country: REDACTED FOR PRIVACY
Tech Phone: REDACTED FOR PRIVACY
Tech Fax: REDACTED FOR PRIVACY
Tech Email: Please contact registrar
Name Server: ns1.cat.xn--q9jyb4c
Name Server: ns2.cat.xn--q9jyb4c
DNSSEC: signedDelegation
URL of the ICANN Whois Inaccuracy Complaint Form: https://www.icann.org/wicf/
>>> Last update of WHOIS database: 2009-06-29T20:13: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.
@@ -1,59 +0,0 @@
Domain Name: cat.みんな
Registry Domain ID: 9-Q9JYB4C
Registrar WHOIS Server: whois.example.com
Registrar URL: http://my.fake.url
Updated Date: 2009-05-29T20:13:00Z
Creation Date: 2000-10-08T00:45:00Z
Registry Expiry Date: 2110-10-08T00:44:59Z
Registrar: Yes Virginia
Registrar IANA ID: 1
Registrar Abuse Contact Email: jakedoe@example.com
Registrar Abuse Contact Phone: +1.2125551216
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
Registry Registrant ID: REDACTED FOR PRIVACY
Registrant Name: REDACTED FOR PRIVACY
Registrant Organization: GOOGLE INCORPORATED <script>
Registrant Street: REDACTED FOR PRIVACY
Registrant City: REDACTED FOR PRIVACY
Registrant State/Province: BM
Registrant Postal Code: REDACTED FOR PRIVACY
Registrant Country: US
Registrant Phone: REDACTED FOR PRIVACY
Registrant Fax: REDACTED FOR PRIVACY
Registrant Email: Please contact registrar
Registry Admin ID: REDACTED FOR PRIVACY
Admin Name: REDACTED FOR PRIVACY
Admin Organization: REDACTED FOR PRIVACY
Admin Street: REDACTED FOR PRIVACY
Admin City: REDACTED FOR PRIVACY
Admin State/Province: REDACTED FOR PRIVACY
Admin Postal Code: REDACTED FOR PRIVACY
Admin Country: REDACTED FOR PRIVACY
Admin Phone: REDACTED FOR PRIVACY
Admin Fax: REDACTED FOR PRIVACY
Admin Email: Please contact registrar
Registry Tech ID: REDACTED FOR PRIVACY
Tech Name: REDACTED FOR PRIVACY
Tech Organization: REDACTED FOR PRIVACY
Tech Street: REDACTED FOR PRIVACY
Tech City: REDACTED FOR PRIVACY
Tech State/Province: REDACTED FOR PRIVACY
Tech Postal Code: REDACTED FOR PRIVACY
Tech Country: REDACTED FOR PRIVACY
Tech Phone: REDACTED FOR PRIVACY
Tech Fax: REDACTED FOR PRIVACY
Tech Email: Please contact registrar
Name Server: ns1.cat.みんな
Name Server: ns2.cat.みんな
DNSSEC: signedDelegation
URL of the ICANN Whois Inaccuracy Complaint Form: https://www.icann.org/wicf/
>>> Last update of WHOIS database: 2009-06-29T20:13: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.
@@ -1,6 +0,0 @@
No nameservers found.
>>> Last update of WHOIS database: 2009-06-29T20:13:00Z <<<
Doodle Disclaimer
I exist so that carriage return
in disclaimer can be tested.
@@ -1,6 +0,0 @@
Malformed path query.
>>> Last update of WHOIS database: 2009-06-29T20:13:00Z <<<
Doodle Disclaimer
I exist so that carriage return
in disclaimer can be tested.
@@ -1,10 +0,0 @@
Server Name: ns1.cat.lol
IP Address: 1.2.3.4
Registrar: The Registrar
Registrar WHOIS Server: whois.nic.fakewhois.example
Registrar URL: http://my.fake.url
>>> Last update of WHOIS database: 2009-06-29T20:13:00Z <<<
Doodle Disclaimer
I exist so that carriage return
in disclaimer can be tested.
@@ -1,6 +0,0 @@
Nameserver not found.
>>> Last update of WHOIS database: 2009-06-29T20:13:00Z <<<
Doodle Disclaimer
I exist so that carriage return
in disclaimer can be tested.
@@ -1,6 +0,0 @@
No WHOIS command specified.
>>> Last update of WHOIS database: 2009-06-29T20:13:00Z <<<
Doodle Disclaimer
I exist so that carriage return
in disclaimer can be tested.
@@ -1,24 +0,0 @@
Registrar: Example Registrar, Inc.
Street: 123 Example Boulevard <script>
City: Williamsburg <script>
State/Province: NY
Postal Code: 11211
Country: US
Phone Number: +1.2125551212
Fax Number: +1.2125551213
Email: contact-us@example.com
Registrar WHOIS Server: whois.example.com
Registrar URL: http://my.fake.url
Admin Contact: Jane Doe
Phone Number: +1.2125551215
Fax Number: +1.2125551216
Email: janedoe@example.com
Technical Contact: John Doe
Phone Number: +1.2125551213
Fax Number: +1.2125551213
Email: johndoe@example.com
>>> Last update of WHOIS database: 2009-06-29T20:13:00Z <<<
Doodle Disclaimer
I exist so that carriage return
in disclaimer can be tested.
@@ -1,6 +0,0 @@
No registrar found.
>>> Last update of WHOIS database: 2009-06-29T20:13:00Z <<<
Doodle Disclaimer
I exist so that carriage return
in disclaimer can be tested.
@@ -1,59 +0,0 @@
Domain Name: cat.lol
Registry Domain ID: 9-LOL
Registrar WHOIS Server: whois.example.com
Registrar URL: http://my.fake.url
Updated Date: 2010-03-06T00:00:00Z
Creation Date: 2000-10-08T00:45:00Z
Registry Expiry Date: 2020-03-01T00:00:00Z
Registrar: Yes Virginia
Registrar IANA ID: 1
Registrar Abuse Contact Email: jakedoe@example.com
Registrar Abuse Contact Phone: +1.2125551216
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
Registry Registrant ID: REDACTED FOR PRIVACY
Registrant Name: REDACTED FOR PRIVACY
Registrant Organization: GOOGLE INCORPORATED <script>
Registrant Street: REDACTED FOR PRIVACY
Registrant City: REDACTED FOR PRIVACY
Registrant State/Province: BM
Registrant Postal Code: REDACTED FOR PRIVACY
Registrant Country: US
Registrant Phone: REDACTED FOR PRIVACY
Registrant Fax: REDACTED FOR PRIVACY
Registrant Email: Please contact registrar
Registry Admin ID: REDACTED FOR PRIVACY
Admin Name: REDACTED FOR PRIVACY
Admin Organization: REDACTED FOR PRIVACY
Admin Street: REDACTED FOR PRIVACY
Admin City: REDACTED FOR PRIVACY
Admin State/Province: REDACTED FOR PRIVACY
Admin Postal Code: REDACTED FOR PRIVACY
Admin Country: REDACTED FOR PRIVACY
Admin Phone: REDACTED FOR PRIVACY
Admin Fax: REDACTED FOR PRIVACY
Admin Email: Please contact registrar
Registry Tech ID: REDACTED FOR PRIVACY
Tech Name: REDACTED FOR PRIVACY
Tech Organization: REDACTED FOR PRIVACY
Tech Street: REDACTED FOR PRIVACY
Tech City: REDACTED FOR PRIVACY
Tech State/Province: REDACTED FOR PRIVACY
Tech Postal Code: REDACTED FOR PRIVACY
Tech Country: REDACTED FOR PRIVACY
Tech Phone: REDACTED FOR PRIVACY
Tech Fax: REDACTED FOR PRIVACY
Tech Email: Please contact registrar
Name Server: ns1.cat.lol
Name Server: ns2.cat.lol
DNSSEC: signedDelegation
URL of the ICANN Whois Inaccuracy Complaint Form: https://www.icann.org/wicf/
>>> Last update of WHOIS database: 2011-01-01T00:00: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.
@@ -1,66 +0,0 @@
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
Registry Registrant ID: REDACTED FOR PRIVACY
Registrant Name: REDACTED FOR PRIVACY
Registrant Organization: Tom & Jerry Corp.
Registrant Street: REDACTED FOR PRIVACY
Registrant City: REDACTED FOR PRIVACY
Registrant State/Province: AP
Registrant Postal Code: REDACTED FOR PRIVACY
Registrant Country: EX
Registrant Phone: REDACTED FOR PRIVACY
Registrant Phone Ext: REDACTED FOR PRIVACY
Registrant Fax: REDACTED FOR PRIVACY
Registrant Fax Ext: REDACTED FOR PRIVACY
Registrant Email: Please contact registrar
Registry Admin ID: REDACTED FOR PRIVACY
Admin Name: REDACTED FOR PRIVACY
Admin Organization: REDACTED FOR PRIVACY
Admin Street: REDACTED FOR PRIVACY
Admin City: REDACTED FOR PRIVACY
Admin State/Province: REDACTED FOR PRIVACY
Admin Postal Code: REDACTED FOR PRIVACY
Admin Country: REDACTED FOR PRIVACY
Admin Phone: REDACTED FOR PRIVACY
Admin Phone Ext: REDACTED FOR PRIVACY
Admin Fax: REDACTED FOR PRIVACY
Admin Email: Please contact registrar
Registry Tech ID: REDACTED FOR PRIVACY
Tech Name: REDACTED FOR PRIVACY
Tech Organization: REDACTED FOR PRIVACY
Tech Street: REDACTED FOR PRIVACY
Tech City: REDACTED FOR PRIVACY
Tech State/Province: REDACTED FOR PRIVACY
Tech Postal Code: REDACTED FOR PRIVACY
Tech Country: REDACTED FOR PRIVACY
Tech Phone: REDACTED FOR PRIVACY
Tech Phone Ext: REDACTED FOR PRIVACY
Tech Fax: REDACTED FOR PRIVACY
Tech Fax Ext: REDACTED FOR PRIVACY
Tech Email: Please contact registrar
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.
@@ -1,66 +0,0 @@
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
Registry Registrant ID: 4-ROID
Registrant Name: EXAMPLE REGISTRANT
Registrant Organization: Tom & Jerry Corp.
Registrant Street: 123 EXAMPLE STREET
Registrant City: ANYTOWN
Registrant State/Province: AP
Registrant Postal Code: A1A1A1
Registrant Country: EX
Registrant Phone: +1.5555551212
Registrant Phone Ext: 1234
Registrant Fax: +1.5555551213
Registrant Fax Ext: 4321
Registrant Email: EMAIL@EXAMPLE.tld
Registry Admin ID: 5-ROID
Admin Name: EXAMPLE REGISTRANT ADMINISTRATIVE
Admin Organization: EXAMPLE REGISTRANT ORGANIZATION
Admin Street: 123 EXAMPLE STREET
Admin City: ANYTOWN
Admin State/Province: AP
Admin Postal Code: A1A1A1
Admin Country: EX
Admin Phone: +1.5555551212
Admin Phone Ext: 1234
Admin Fax: +1.5555551213
Admin Email: EMAIL@EXAMPLE.tld
Registry Tech ID: 6-ROID
Tech Name: EXAMPLE REGISTRAR TECHNICAL
Tech Organization: EXAMPLE REGISTRAR LLC
Tech Street: 123 EXAMPLE STREET
Tech City: ANYTOWN
Tech State/Province: AP
Tech Postal Code: A1A1A1
Tech Country: EX
Tech Phone: +1.1235551234
Tech Phone Ext: 1234
Tech Fax: +1.5555551213
Tech Fax Ext: 93
Tech Email: EMAIL@EXAMPLE.tld
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.
@@ -1,28 +0,0 @@
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.
@@ -1,53 +0,0 @@
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
Registry Admin ID: REDACTED FOR PRIVACY
Admin Name: REDACTED FOR PRIVACY
Admin Organization: REDACTED FOR PRIVACY
Admin Street: REDACTED FOR PRIVACY
Admin City: REDACTED FOR PRIVACY
Admin State/Province: REDACTED FOR PRIVACY
Admin Postal Code: REDACTED FOR PRIVACY
Admin Country: REDACTED FOR PRIVACY
Admin Phone: REDACTED FOR PRIVACY
Admin Phone Ext: REDACTED FOR PRIVACY
Admin Fax: REDACTED FOR PRIVACY
Admin Email: Please contact registrar
Registry Tech ID: REDACTED FOR PRIVACY
Tech Name: REDACTED FOR PRIVACY
Tech Organization: REDACTED FOR PRIVACY
Tech Street: REDACTED FOR PRIVACY
Tech City: REDACTED FOR PRIVACY
Tech State/Province: REDACTED FOR PRIVACY
Tech Postal Code: REDACTED FOR PRIVACY
Tech Country: REDACTED FOR PRIVACY
Tech Phone: REDACTED FOR PRIVACY
Tech Phone Ext: REDACTED FOR PRIVACY
Tech Fax: REDACTED FOR PRIVACY
Tech Fax Ext: REDACTED FOR PRIVACY
Tech Email: Please contact registrar
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.
@@ -1,64 +0,0 @@
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:
Registrar Abuse Contact Phone:
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
Registry Registrant ID: REDACTED FOR PRIVACY
Registrant Name: REDACTED FOR PRIVACY
Registrant Organization: Tom & Jerry Corp.
Registrant Street: REDACTED FOR PRIVACY
Registrant City: REDACTED FOR PRIVACY
Registrant State/Province: AP
Registrant Postal Code: REDACTED FOR PRIVACY
Registrant Country: EX
Registrant Phone: REDACTED FOR PRIVACY
Registrant Phone Ext: REDACTED FOR PRIVACY
Registrant Fax: REDACTED FOR PRIVACY
Registrant Fax Ext: REDACTED FOR PRIVACY
Registrant Email: Please contact registrar
Registry Admin ID: REDACTED FOR PRIVACY
Admin Name: REDACTED FOR PRIVACY
Admin Organization: REDACTED FOR PRIVACY
Admin Street: REDACTED FOR PRIVACY
Admin City: REDACTED FOR PRIVACY
Admin State/Province: REDACTED FOR PRIVACY
Admin Postal Code: REDACTED FOR PRIVACY
Admin Country: REDACTED FOR PRIVACY
Admin Phone: REDACTED FOR PRIVACY
Admin Phone Ext: REDACTED FOR PRIVACY
Admin Fax: REDACTED FOR PRIVACY
Admin Email: Please contact registrar
Registry Tech ID: REDACTED FOR PRIVACY
Tech Name: REDACTED FOR PRIVACY
Tech Organization: REDACTED FOR PRIVACY
Tech Street: REDACTED FOR PRIVACY
Tech City: REDACTED FOR PRIVACY
Tech State/Province: REDACTED FOR PRIVACY
Tech Postal Code: REDACTED FOR PRIVACY
Tech Country: REDACTED FOR PRIVACY
Tech Phone: REDACTED FOR PRIVACY
Tech Phone Ext: REDACTED FOR PRIVACY
Tech Fax: REDACTED FOR PRIVACY
Tech Fax Ext: REDACTED FOR PRIVACY
Tech Email: Please contact registrar
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
Footer
@@ -1,18 +0,0 @@
Server Name: ns1.example.tld
IP Address: 192.0.2.123
IP Address: 2001:db8::1
Registrar: Hänsel & Gretel Registrar, Inc.
Registrar WHOIS Server: whois.nic.fakewhois.example
Registrar URL: http://my.fake.url
Server Name: ns2.example.tld
IP Address: 192.0.2.123
IP Address: 2001:db8::1
Registrar: Hänsel & Gretel Registrar, Inc.
Registrar WHOIS Server: whois.nic.fakewhois.example
Registrar URL: http://my.fake.url
>>> Last update of WHOIS database: 2009-05-29T20:15:00Z <<<
Doodle Disclaimer
I exist so that carriage return
in disclaimer can be tested.
@@ -1,11 +0,0 @@
Server Name: ns1.example.tld
IP Address: 192.0.2.123
IP Address: 2001:db8::1
Registrar: Hänsel & Gretel Registrar, Inc.
Registrar WHOIS Server: whois.nic.fakewhois.example
Registrar URL: http://my.fake.url
>>> Last update of WHOIS database: 2009-05-29T20:15:00Z <<<
Doodle Disclaimer
I exist so that carriage return
in disclaimer can be tested.
@@ -1,28 +0,0 @@
Registrar: Example Registrar, Inc.
Street: 1234 Admiralty Way
City: Marina del Rey
State/Province: CA
Postal Code: 90292
Country: US
Phone Number: +1.3105551212
Fax Number: +1.3105551213
Email: registrar@example.tld
Registrar WHOIS Server: whois.example-registrar.tld
Registrar URL: http://my.fake.url
Admin Contact: Jane Registrar
Phone Number: +1.3105551214
Fax Number: +1.3105551213
Email: janeregistrar@example-registrar.tld
Admin Contact: Joe Registrar
Phone Number: +1.3105551213
Fax Number: +1.3105551213
Email: joeregistrar@example-registrar.tld
Technical Contact: Bonnie & Clyde
Phone Number: +1.3105551215
Fax Number: +1.3105551216
Email: johngeek@example-registrar.tld
>>> Last update of WHOIS database: 2009-05-29T20:15:00Z <<<
Doodle Disclaimer
I exist so that carriage return
in disclaimer can be tested.
@@ -1,11 +0,0 @@
Server Name: ns1.zobo.tld
IP Address: 192.0.2.123
IP Address: 2001:db8::1
Registrar: The Registrar
Registrar WHOIS Server: whois.nic.fakewhois.example
Registrar URL: http://my.fake.url
>>> Last update of WHOIS database: 2009-05-29T20:15:00Z <<<
Doodle Disclaimer
I exist so that carriage return
in disclaimer can be tested.