1
0
mirror of https://github.com/google/nomulus synced 2026-01-04 04:04:22 +00:00

Include GP statuses in RDAP results (#2606)

We do this for WHOIS results so we should do it for RDAP results as well
(especially since they're mostly already included in the response
profile).
This commit is contained in:
gbrodman
2024-12-09 14:55:16 -05:00
committed by GitHub
parent cb3738d540
commit 8e41278717
11 changed files with 987 additions and 56 deletions

View File

@@ -31,18 +31,21 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
import com.google.common.collect.Streams;
import com.google.common.flogger.FluentLogger;
import com.google.common.net.InetAddresses;
import com.google.gson.JsonArray;
import google.registry.config.RegistryConfig.Config;
import google.registry.model.EppResource;
import google.registry.model.adapters.EnumToAttributeAdapter.EppEnum;
import google.registry.model.contact.Contact;
import google.registry.model.contact.ContactPhoneNumber;
import google.registry.model.contact.PostalInfo;
import google.registry.model.domain.DesignatedContact;
import google.registry.model.domain.DesignatedContact.Type;
import google.registry.model.domain.Domain;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.eppcommon.Address;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.Host;
@@ -175,10 +178,8 @@ public class RdapJsonFormatter {
+ " repoId = '%repoIdValue%' and type is not null group by type)";
/** Map of EPP status values to the RDAP equivalents. */
private static final ImmutableMap<StatusValue, RdapStatus> STATUS_TO_RDAP_STATUS_MAP =
new ImmutableMap.Builder<StatusValue, RdapStatus>()
// RdapStatus.ADD_PERIOD not defined in our system
// RdapStatus.AUTO_RENEW_PERIOD not defined in our system
private static final ImmutableMap<EppEnum, RdapStatus> STATUS_TO_RDAP_STATUS_MAP =
new ImmutableMap.Builder<EppEnum, RdapStatus>()
.put(StatusValue.CLIENT_DELETE_PROHIBITED, RdapStatus.CLIENT_DELETE_PROHIBITED)
.put(StatusValue.CLIENT_HOLD, RdapStatus.CLIENT_HOLD)
.put(StatusValue.CLIENT_RENEW_PROHIBITED, RdapStatus.CLIENT_RENEW_PROHIBITED)
@@ -190,17 +191,21 @@ public class RdapJsonFormatter {
.put(StatusValue.PENDING_CREATE, RdapStatus.PENDING_CREATE)
.put(StatusValue.PENDING_DELETE, RdapStatus.PENDING_DELETE)
// RdapStatus.PENDING_RENEW not defined in our system
// RdapStatus.PENDING_RESTORE not defined in our system
.put(StatusValue.PENDING_TRANSFER, RdapStatus.PENDING_TRANSFER)
.put(StatusValue.PENDING_UPDATE, RdapStatus.PENDING_UPDATE)
// RdapStatus.REDEMPTION_PERIOD not defined in our system
// RdapStatus.RENEW_PERIOD not defined in our system
.put(StatusValue.SERVER_DELETE_PROHIBITED, RdapStatus.SERVER_DELETE_PROHIBITED)
.put(StatusValue.SERVER_HOLD, RdapStatus.SERVER_HOLD)
.put(StatusValue.SERVER_RENEW_PROHIBITED, RdapStatus.SERVER_RENEW_PROHIBITED)
.put(StatusValue.SERVER_TRANSFER_PROHIBITED, RdapStatus.SERVER_TRANSFER_PROHIBITED)
.put(StatusValue.SERVER_UPDATE_PROHIBITED, RdapStatus.SERVER_UPDATE_PROHIBITED)
// RdapStatus.TRANSFER_PERIOD not defined in our system
.put(GracePeriodStatus.ADD, RdapStatus.ADD_PERIOD)
.put(GracePeriodStatus.AUTO_RENEW, RdapStatus.AUTO_RENEW_PERIOD)
.put(GracePeriodStatus.REDEMPTION, RdapStatus.REDEMPTION_PERIOD)
.put(GracePeriodStatus.RENEW, RdapStatus.RENEW_PERIOD)
.put(GracePeriodStatus.PENDING_DELETE, RdapStatus.PENDING_DELETE)
// In practice, PENDING_RESTORE is unused. We just perform the restore immediately
.put(GracePeriodStatus.PENDING_RESTORE, RdapStatus.PENDING_RESTORE)
.put(GracePeriodStatus.TRANSFER, RdapStatus.TRANSFER_PERIOD)
.build();
/**
@@ -348,9 +353,11 @@ public class RdapJsonFormatter {
}
// RDAP Response Profile 2.6.1: must have at least one status member
// makeStatusValueList should in theory always contain one of either "active" or "inactive".
Set<EppEnum> allStatusValues =
Sets.union(domain.getStatusValues(), domain.getGracePeriodStatuses());
ImmutableSet<RdapStatus> status =
makeStatusValueList(
domain.getStatusValues(),
allStatusValues,
false, // isRedacted
domain.getDeletionTime().isBefore(getRequestTime()));
builder.statusBuilder().addAll(status);
@@ -1045,7 +1052,7 @@ public class RdapJsonFormatter {
* redacted objects.
*/
private static ImmutableSet<RdapStatus> makeStatusValueList(
ImmutableSet<StatusValue> statusValues, boolean isRedacted, boolean isDeleted) {
Set<? extends EppEnum> statusValues, boolean isRedacted, boolean isDeleted) {
Stream<RdapStatus> stream =
statusValues.stream()
.map(status -> STATUS_TO_RDAP_STATUS_MAP.getOrDefault(status, RdapStatus.OBSCURED));

View File

@@ -51,7 +51,7 @@ final class RdapObjectClasses {
*/
@RestrictJsonNames({})
@AutoValue
abstract static class Vcard implements Jsonable {
public abstract static class Vcard implements Jsonable {
abstract String property();
abstract ImmutableMap<String, ImmutableList<String>> parameters();
abstract String valueType();
@@ -94,7 +94,7 @@ final class RdapObjectClasses {
@RestrictJsonNames("vcardArray")
@AutoValue
abstract static class VcardArray implements Jsonable {
public abstract static class VcardArray implements Jsonable {
private static final String VCARD_VERSION_NUMBER = "4.0";
private static final Vcard VCARD_ENTRY_VERSION =
@@ -148,7 +148,7 @@ final class RdapObjectClasses {
*
* <p>All Actions need to return an object of this type.
*/
abstract static class ReplyPayloadBase extends AbstractJsonableObject {
public abstract static class ReplyPayloadBase extends AbstractJsonableObject {
final BoilerplateType boilerplateType;
ReplyPayloadBase(BoilerplateType boilerplateType) {
@@ -165,7 +165,7 @@ final class RdapObjectClasses {
*/
@AutoValue
@RestrictJsonNames({})
abstract static class TopLevelReplyObject extends AbstractJsonableObject {
public abstract static class TopLevelReplyObject extends AbstractJsonableObject {
@JsonableElement("rdapConformance")
static final RdapConformance RDAP_CONFORMANCE = RdapConformance.INSTANCE;
@@ -257,7 +257,7 @@ final class RdapObjectClasses {
* <p>We're missing the "autnums" and "networks" fields
*/
@RestrictJsonNames({"entities[]", "entitySearchResults[]"})
abstract static class RdapEntity extends RdapObjectBase {
public abstract static class RdapEntity extends RdapObjectBase {
/** Role values specified in RFC 9083 § 10.2.4. */
@RestrictJsonNames("roles[]")
@@ -311,7 +311,7 @@ final class RdapObjectClasses {
* for each one for type safety.
*/
@AutoValue
abstract static class RdapRegistrarEntity extends RdapEntity {
public abstract static class RdapRegistrarEntity extends RdapEntity {
static Builder builder() {
return new AutoValue_RdapObjectClasses_RdapRegistrarEntity.Builder();
@@ -330,7 +330,7 @@ final class RdapObjectClasses {
* for each one for type safety.
*/
@AutoValue
abstract static class RdapContactEntity extends RdapEntity {
public abstract static class RdapContactEntity extends RdapEntity {
static Builder builder() {
return new AutoValue_RdapObjectClasses_RdapContactEntity.Builder();
@@ -387,7 +387,7 @@ final class RdapObjectClasses {
/** The Nameserver Object Class defined in 5.2 of RFC 9083. */
@RestrictJsonNames({"nameservers[]", "nameserverSearchResults[]"})
@AutoValue
abstract static class RdapNameserver extends RdapNamedObjectBase {
public abstract static class RdapNameserver extends RdapNamedObjectBase {
@JsonableElement Optional<IpAddresses> ipAddresses() {
if (ipv6().isEmpty() && ipv4().isEmpty()) {
@@ -429,7 +429,7 @@ final class RdapObjectClasses {
/** Object defined in RFC 9083 section 5.3, only used for RdapDomain. */
@RestrictJsonNames("secureDNS")
@AutoValue
abstract static class SecureDns extends AbstractJsonableObject {
public abstract static class SecureDns extends AbstractJsonableObject {
@RestrictJsonNames("dsData[]")
@AutoValue
abstract static class DsData extends AbstractJsonableObject {
@@ -507,7 +507,7 @@ final class RdapObjectClasses {
*/
@RestrictJsonNames("domainSearchResults[]")
@AutoValue
abstract static class RdapDomain extends RdapNamedObjectBase {
public abstract static class RdapDomain extends RdapNamedObjectBase {
@JsonableElement abstract ImmutableList<RdapNameserver> nameservers();
@@ -535,7 +535,7 @@ final class RdapObjectClasses {
/** Error Response Body defined in 6 of RFC 9083. */
@RestrictJsonNames({})
@AutoValue
abstract static class ErrorResponse extends ReplyPayloadBase {
public abstract static class ErrorResponse extends ReplyPayloadBase {
@JsonableElement final LanguageIdentifier lang = LanguageIdentifier.EN;
@@ -561,7 +561,7 @@ final class RdapObjectClasses {
*/
@RestrictJsonNames({})
@AutoValue
abstract static class HelpResponse extends ReplyPayloadBase {
public abstract static class HelpResponse extends ReplyPayloadBase {
@JsonableElement("notices[]") abstract Optional<Notice> helpNotice();
HelpResponse() {

View File

@@ -42,9 +42,11 @@ import org.junit.jupiter.api.extension.RegisterExtension;
/** Common unit test code for actions inheriting {@link RdapActionBase}. */
abstract class RdapActionBaseTestCase<A extends RdapActionBase> {
protected final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01TZ"));
@RegisterExtension
final JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
protected static final AuthResult AUTH_RESULT =
AuthResult.createUser(
@@ -61,7 +63,6 @@ abstract class RdapActionBaseTestCase<A extends RdapActionBase> {
.build());
protected FakeResponse response = new FakeResponse();
protected final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01TZ"));
final RdapMetrics rdapMetrics = mock(RdapMetrics.class);
RdapAuthorization.Role metricRole = PUBLIC;

View File

@@ -17,6 +17,8 @@ package google.registry.rdap;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.EppResourceUtils.loadByForeignKey;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
import static google.registry.testing.DatabaseHelper.persistDomainWithDependentResources;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.testing.DatabaseHelper.persistSimpleResources;
import static google.registry.testing.FullFieldsTestEntityHelper.makeAndPersistHost;
@@ -31,7 +33,10 @@ import com.google.common.collect.ImmutableSet;
import com.google.gson.JsonObject;
import google.registry.model.contact.Contact;
import google.registry.model.domain.Domain;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.Period;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.Host;
import google.registry.model.registrar.Registrar;
import google.registry.model.reporting.HistoryEntry;
@@ -43,6 +48,7 @@ import google.registry.rdap.RdapSearchResults.IncompletenessWarningType;
import google.registry.request.Action;
import google.registry.testing.FullFieldsTestEntityHelper;
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;
@@ -59,6 +65,9 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
super(RdapDomainAction.class);
}
private Contact registrantLol;
private Host host1;
@BeforeEach
void beforeEach() {
// lol
@@ -66,7 +75,7 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
Registrar registrarLol = persistResource(makeRegistrar(
"evilregistrar", "Yes Virginia <script>", Registrar.State.ACTIVE));
persistSimpleResources(makeRegistrarPocs(registrarLol));
Contact registrantLol =
registrantLol =
FullFieldsTestEntityHelper.makeAndPersistContact(
"5372808-ERL",
"Goblin Market",
@@ -83,7 +92,7 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
Contact techContactLol =
FullFieldsTestEntityHelper.makeAndPersistContact(
"5372808-TRL", "The Raven", "bog@cat.lol", clock.nowUtc().minusYears(3), registrarLol);
Host host1 = makeAndPersistHost("ns1.cat.lol", "1.2.3.4", null, clock.nowUtc().minusYears(1));
host1 = makeAndPersistHost("ns1.cat.lol", "1.2.3.4", null, clock.nowUtc().minusYears(1));
Host host2 =
makeAndPersistHost(
"ns2.cat.lol", "bad:f00d:cafe:0:0:0:15:beef", clock.nowUtc().minusYears(2));
@@ -493,6 +502,93 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
assertThat(response.getStatus()).isEqualTo(200);
}
@Test
void testAddGracePeriod() {
persistActiveDomainWithHost(
"addgraceperiod", "lol", clock.nowUtc(), clock.nowUtc().plusYears(1));
assertAboutJson()
.that(generateActualJson("addgraceperiod.lol"))
.isEqualTo(addBoilerplate(jsonFileBuilder().load("rdap_domain_add_grace_period.json")));
}
@Test
void testAutoRenewGracePeriod() {
persistActiveDomainWithHost(
"autorenew", "lol", clock.nowUtc().minusYears(1).minusDays(1), clock.nowUtc().minusDays(1));
assertAboutJson()
.that(generateActualJson("autorenew.lol"))
.isEqualTo(
addBoilerplate(jsonFileBuilder().load("rdap_domain_auto_renew_grace_period.json")));
}
@Test
void testRedemptionGracePeriod() {
Domain domain = persistActiveDomain("redemption.lol", clock.nowUtc().minusYears(1));
persistResource(
domain
.asBuilder()
.addNameserver(host1.createVKey())
.setDeletionTime(clock.nowUtc().plusDays(1))
.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE))
.setGracePeriods(
ImmutableSet.of(
GracePeriod.createWithoutBillingEvent(
GracePeriodStatus.REDEMPTION,
domain.getRepoId(),
clock.nowUtc().plusDays(4),
"TheRegistrar")))
.build());
assertAboutJson()
.that(generateActualJson("redemption.lol"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder().load("rdap_domain_pending_delete_redemption_grace_period.json")));
}
@Test
void testRenewGracePeriod() {
Domain domain =
persistActiveDomainWithHost(
"renew", "lol", clock.nowUtc().minusYears(1), clock.nowUtc().plusYears(1));
persistResource(
domain
.asBuilder()
.addGracePeriod(
GracePeriod.create(
GracePeriodStatus.RENEW,
domain.getRepoId(),
clock.nowUtc().plusDays(1),
"TheRegistrar",
null))
.build());
assertAboutJson()
.that(generateActualJson("renew.lol"))
.isEqualTo(
addBoilerplate(jsonFileBuilder().load("rdap_domain_explicit_renew_grace_period.json")));
}
@Test
void testTransferGracePeriod() {
Domain domain =
persistActiveDomainWithHost(
"transfer", "lol", clock.nowUtc().minusMonths(6), clock.nowUtc().plusYears(1));
persistResource(
domain
.asBuilder()
.addGracePeriod(
GracePeriod.create(
GracePeriodStatus.TRANSFER,
domain.getRepoId(),
clock.nowUtc().plusDays(1),
"TheRegistrar",
null))
.build());
assertAboutJson()
.that(generateActualJson("transfer.lol"))
.isEqualTo(
addBoilerplate(jsonFileBuilder().load("rdap_domain_transfer_grace_period.json")));
}
@Test
void testMetrics() {
generateActualJson("cat.lol");
@@ -511,4 +607,14 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
.setIncompletenessWarningType(IncompletenessWarningType.COMPLETE)
.build());
}
private Domain persistActiveDomainWithHost(
String label, String tld, DateTime creationTime, DateTime expirationTime) {
return persistResource(
persistDomainWithDependentResources(
label, tld, registrantLol, clock.nowUtc(), creationTime, expirationTime)
.asBuilder()
.addNameserver(host1.createVKey())
.build());
}
}

View File

@@ -124,6 +124,7 @@ import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.Duration;
/** Static utils for setting up test resources. */
public final class DatabaseHelper {
@@ -593,30 +594,36 @@ public final class DatabaseHelper {
DateTime expirationTime) {
String domainName = String.format("%s.%s", label, tld);
String repoId = generateNewDomainRoid(tld);
Domain domain =
persistResource(
new Domain.Builder()
.setRepoId(repoId)
.setDomainName(domainName)
.setPersistedCurrentSponsorRegistrarId("TheRegistrar")
.setCreationRegistrarId("TheRegistrar")
.setCreationTimeForTest(creationTime)
.setRegistrationExpirationTime(expirationTime)
.setRegistrant(Optional.of(contact.createVKey()))
.setContacts(
ImmutableSet.of(
DesignatedContact.create(Type.ADMIN, contact.createVKey()),
DesignatedContact.create(Type.TECH, contact.createVKey())))
.setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("fooBAR")))
.addGracePeriod(
GracePeriod.create(
GracePeriodStatus.ADD, repoId, now.plusDays(10), "TheRegistrar", null))
.build());
Domain.Builder domainBuilder =
new Domain.Builder()
.setRepoId(repoId)
.setDomainName(domainName)
.setPersistedCurrentSponsorRegistrarId("TheRegistrar")
.setCreationRegistrarId("TheRegistrar")
.setCreationTimeForTest(creationTime)
.setRegistrationExpirationTime(expirationTime)
.setRegistrant(Optional.of(contact.createVKey()))
.setContacts(
ImmutableSet.of(
DesignatedContact.create(Type.ADMIN, contact.createVKey()),
DesignatedContact.create(Type.TECH, contact.createVKey())))
.setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("fooBAR")));
Duration addGracePeriodLength = Tld.get(tld).getAddGracePeriodLength();
if (creationTime.plus(addGracePeriodLength).isAfter(now)) {
domainBuilder.addGracePeriod(
GracePeriod.create(
GracePeriodStatus.ADD,
repoId,
creationTime.plus(addGracePeriodLength),
"TheRegistrar",
null));
}
Domain domain = persistResource(domainBuilder.build());
DomainHistory historyEntryDomainCreate =
persistResource(
new DomainHistory.Builder()
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setModificationTime(now)
.setModificationTime(creationTime)
.setDomain(domain)
.setRegistrarId(domain.getCreationRegistrarId())
.build());

View File

@@ -108,9 +108,10 @@ public class ConsoleBulkDomainActionTest {
assertThat(fakeResponse.getStatus()).isEqualTo(SC_OK);
assertThat(fakeResponse.getPayload())
.isEqualTo(
"{\"example.tld\":{\"message\":\"Command completed"
+ " successfully\",\"responseCode\":1000}}");
assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(clock.nowUtc());
"""
{"example.tld":{"message":"Command completed successfully; action pending",\
"responseCode":1001}}""");
assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(clock.nowUtc().plusDays(35));
}
@Test
@@ -132,8 +133,8 @@ public class ConsoleBulkDomainActionTest {
assertThat(fakeResponse.getStatus()).isEqualTo(SC_OK);
assertThat(fakeResponse.getPayload())
.isEqualTo(
"{\"example.tld\":{\"message\":\"Command completed"
+ " successfully\",\"responseCode\":1000}}");
"""
{"example.tld":{"message":"Command completed successfully","responseCode":1000}}""");
assertThat(loadByEntity(domain).getStatusValues())
.containsAtLeast(
StatusValue.SERVER_RENEW_PROHIBITED,
@@ -158,11 +159,11 @@ public class ConsoleBulkDomainActionTest {
assertThat(fakeResponse.getStatus()).isEqualTo(SC_OK);
assertThat(fakeResponse.getPayload())
.isEqualTo(
"{\"example.tld\":{\"message\":\"Command completed"
+ " successfully\",\"responseCode\":1000},\"nonexistent.tld\":{\"message\":\"The"
+ " domain with given ID (nonexistent.tld) doesn\\u0027t"
+ " exist.\",\"responseCode\":2303}}");
assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(clock.nowUtc());
"""
{"example.tld":{"message":"Command completed successfully; action pending","responseCode":1001},\
"nonexistent.tld":{"message":"The domain with given ID (nonexistent.tld) doesn\\u0027t exist.",\
"responseCode":2303}}""");
assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(clock.nowUtc().plusDays(35));
}
@Test

View File

@@ -0,0 +1,161 @@
{
"rdapConformance": [
"rdap_level_0",
"icann_rdap_response_profile_0",
"icann_rdap_technical_implementation_guide_0"
],
"objectClassName": "domain",
"entities": [
{
"objectClassName": "entity",
"handle": "1",
"links": [
{
"href": "https://example.tld/rdap/entity/1",
"rel": "self",
"type": "application/rdap+json"
}
],
"publicIds": [
{
"identifier": "1",
"type": "IANA Registrar ID"
}
],
"remarks": [
{
"description": [
"Summary data only. For complete data, send a specific query for the object."
],
"title": "Incomplete Data",
"type": "object truncated due to unexplainable reasons"
}
],
"roles": [
"registrar"
],
"vcardArray": [
"vcard",
[
[
"version",
{},
"text",
"4.0"
],
[
"fn",
{},
"text",
"The Registrar"
]
]
]
},
{
"objectClassName": "entity",
"handle": "",
"remarks": [
{
"description": [
"Some of the data in this object has been removed.",
"Contact personal data is visible only to the owning registrar."
],
"links": [
{
"href": "https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel": "alternate",
"type": "text/html"
}
],
"title": "REDACTED FOR PRIVACY",
"type": "object redacted due to authorization"
},
{
"description": [
"Please query the RDDS service of the Registrar of Record identifies in this output for information on how to contact the Registrant of the queried domain name."
],
"title": "EMAIL REDACTED FOR PRIVACY",
"type": "object redacted due to authorization"
}
],
"roles": [
"administrative",
"technical",
"registrant"
],
"vcardArray": [
"vcard",
[
[
"version",
{},
"text",
"4.0"
],
[
"fn",
{},
"text",
""
]
]
]
}
],
"events": [
{
"eventAction": "registration",
"eventActor": "TheRegistrar",
"eventDate": "2000-01-01T00:00:00.000Z"
},
{
"eventAction": "expiration",
"eventDate": "2001-01-01T00:00:00.000Z"
},
{
"eventAction": "last update of RDAP database",
"eventDate": "2000-01-01T00:00:00.000Z"
}
],
"handle": "28-LOL",
"ldhName": "addgraceperiod.lol",
"links": [
{
"href": "https://example.tld/rdap/domain/addgraceperiod.lol",
"rel": "self",
"type": "application/rdap+json"
}
],
"nameservers": [
{
"objectClassName": "nameserver",
"handle": "8-ROID",
"ldhName": "ns1.cat.lol",
"links": [
{
"href": "https://example.tld/rdap/nameserver/ns1.cat.lol",
"rel": "self",
"type": "application/rdap+json"
}
],
"remarks": [
{
"description": [
"Summary data only. For complete data, send a specific query for the object."
],
"title": "Incomplete Data",
"type": "object truncated due to unexplainable reasons"
}
]
}
],
"secureDNS": {
"delegationSigned": false,
"zoneSigned": true
},
"status": [
"active",
"add period"
]
}

View File

@@ -0,0 +1,165 @@
{
"rdapConformance": [
"rdap_level_0",
"icann_rdap_response_profile_0",
"icann_rdap_technical_implementation_guide_0"
],
"objectClassName": "domain",
"entities": [
{
"objectClassName": "entity",
"handle": "1",
"links": [
{
"href": "https://example.tld/rdap/entity/1",
"rel": "self",
"type": "application/rdap+json"
}
],
"publicIds": [
{
"identifier": "1",
"type": "IANA Registrar ID"
}
],
"remarks": [
{
"description": [
"Summary data only. For complete data, send a specific query for the object."
],
"title": "Incomplete Data",
"type": "object truncated due to unexplainable reasons"
}
],
"roles": [
"registrar"
],
"vcardArray": [
"vcard",
[
[
"version",
{},
"text",
"4.0"
],
[
"fn",
{},
"text",
"The Registrar"
]
]
]
},
{
"objectClassName": "entity",
"handle": "",
"remarks": [
{
"description": [
"Some of the data in this object has been removed.",
"Contact personal data is visible only to the owning registrar."
],
"links": [
{
"href": "https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel": "alternate",
"type": "text/html"
}
],
"title": "REDACTED FOR PRIVACY",
"type": "object redacted due to authorization"
},
{
"description": [
"Please query the RDDS service of the Registrar of Record identifies in this output for information on how to contact the Registrant of the queried domain name."
],
"title": "EMAIL REDACTED FOR PRIVACY",
"type": "object redacted due to authorization"
}
],
"roles": [
"administrative",
"technical",
"registrant"
],
"vcardArray": [
"vcard",
[
[
"version",
{},
"text",
"4.0"
],
[
"fn",
{},
"text",
""
]
]
]
}
],
"events": [
{
"eventAction": "registration",
"eventActor": "TheRegistrar",
"eventDate": "1998-12-31T00:00:00.000Z"
},
{
"eventAction": "expiration",
"eventDate": "2000-12-31T00:00:00.000Z"
},
{
"eventAction": "last update of RDAP database",
"eventDate": "2000-01-01T00:00:00.000Z"
},
{
"eventAction": "last changed",
"eventDate": "1999-12-31T00:00:00.000Z"
}
],
"handle": "28-LOL",
"ldhName": "autorenew.lol",
"links": [
{
"href": "https://example.tld/rdap/domain/autorenew.lol",
"rel": "self",
"type": "application/rdap+json"
}
],
"nameservers": [
{
"objectClassName": "nameserver",
"handle": "8-ROID",
"ldhName": "ns1.cat.lol",
"links": [
{
"href": "https://example.tld/rdap/nameserver/ns1.cat.lol",
"rel": "self",
"type": "application/rdap+json"
}
],
"remarks": [
{
"description": [
"Summary data only. For complete data, send a specific query for the object."
],
"title": "Incomplete Data",
"type": "object truncated due to unexplainable reasons"
}
]
}
],
"secureDNS": {
"delegationSigned": false,
"zoneSigned": true
},
"status": [
"active",
"auto renew period"
]
}

View File

@@ -0,0 +1,161 @@
{
"rdapConformance": [
"rdap_level_0",
"icann_rdap_response_profile_0",
"icann_rdap_technical_implementation_guide_0"
],
"objectClassName": "domain",
"entities": [
{
"objectClassName": "entity",
"handle": "1",
"links": [
{
"href": "https://example.tld/rdap/entity/1",
"rel": "self",
"type": "application/rdap+json"
}
],
"publicIds": [
{
"identifier": "1",
"type": "IANA Registrar ID"
}
],
"remarks": [
{
"description": [
"Summary data only. For complete data, send a specific query for the object."
],
"title": "Incomplete Data",
"type": "object truncated due to unexplainable reasons"
}
],
"roles": [
"registrar"
],
"vcardArray": [
"vcard",
[
[
"version",
{},
"text",
"4.0"
],
[
"fn",
{},
"text",
"The Registrar"
]
]
]
},
{
"objectClassName": "entity",
"handle": "",
"remarks": [
{
"description": [
"Some of the data in this object has been removed.",
"Contact personal data is visible only to the owning registrar."
],
"links": [
{
"href": "https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel": "alternate",
"type": "text/html"
}
],
"title": "REDACTED FOR PRIVACY",
"type": "object redacted due to authorization"
},
{
"description": [
"Please query the RDDS service of the Registrar of Record identifies in this output for information on how to contact the Registrant of the queried domain name."
],
"title": "EMAIL REDACTED FOR PRIVACY",
"type": "object redacted due to authorization"
}
],
"roles": [
"administrative",
"technical",
"registrant"
],
"vcardArray": [
"vcard",
[
[
"version",
{},
"text",
"4.0"
],
[
"fn",
{},
"text",
""
]
]
]
}
],
"events": [
{
"eventAction": "registration",
"eventActor": "TheRegistrar",
"eventDate": "1999-01-01T00:00:00.000Z"
},
{
"eventAction": "expiration",
"eventDate": "2001-01-01T00:00:00.000Z"
},
{
"eventAction": "last update of RDAP database",
"eventDate": "2000-01-01T00:00:00.000Z"
}
],
"handle": "28-LOL",
"ldhName": "renew.lol",
"links": [
{
"href": "https://example.tld/rdap/domain/renew.lol",
"rel": "self",
"type": "application/rdap+json"
}
],
"nameservers": [
{
"objectClassName": "nameserver",
"handle": "8-ROID",
"ldhName": "ns1.cat.lol",
"links": [
{
"href": "https://example.tld/rdap/nameserver/ns1.cat.lol",
"rel": "self",
"type": "application/rdap+json"
}
],
"remarks": [
{
"description": [
"Summary data only. For complete data, send a specific query for the object."
],
"title": "Incomplete Data",
"type": "object truncated due to unexplainable reasons"
}
]
}
],
"secureDNS": {
"delegationSigned": false,
"zoneSigned": true
},
"status": [
"active",
"renew period"
]
}

View File

@@ -0,0 +1,161 @@
{
"rdapConformance": [
"rdap_level_0",
"icann_rdap_response_profile_0",
"icann_rdap_technical_implementation_guide_0"
],
"objectClassName": "domain",
"entities": [
{
"objectClassName": "entity",
"handle": "1",
"links": [
{
"href": "https://example.tld/rdap/entity/1",
"rel": "self",
"type": "application/rdap+json"
}
],
"publicIds": [
{
"identifier": "1",
"type": "IANA Registrar ID"
}
],
"remarks": [
{
"description": [
"Summary data only. For complete data, send a specific query for the object."
],
"title": "Incomplete Data",
"type": "object truncated due to unexplainable reasons"
}
],
"roles": [
"registrar"
],
"vcardArray": [
"vcard",
[
[
"version",
{},
"text",
"4.0"
],
[
"fn",
{},
"text",
"The Registrar"
]
]
]
},
{
"objectClassName": "entity",
"handle": "",
"remarks": [
{
"description": [
"Some of the data in this object has been removed.",
"Contact personal data is visible only to the owning registrar."
],
"links": [
{
"href": "https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel": "alternate",
"type": "text/html"
}
],
"title": "REDACTED FOR PRIVACY",
"type": "object redacted due to authorization"
},
{
"description": [
"Please query the RDDS service of the Registrar of Record identifies in this output for information on how to contact the Registrant of the queried domain name."
],
"title": "EMAIL REDACTED FOR PRIVACY",
"type": "object redacted due to authorization"
}
],
"roles": [
"administrative",
"technical",
"registrant"
],
"vcardArray": [
"vcard",
[
[
"version",
{},
"text",
"4.0"
],
[
"fn",
{},
"text",
""
]
]
]
}
],
"events": [
{
"eventAction": "registration",
"eventActor": "TheRegistrar",
"eventDate": "1999-01-01T00:00:00.000Z"
},
{
"eventAction": "expiration",
"eventDate": "294247-01-10T04:00:54.775Z"
},
{
"eventAction": "last update of RDAP database",
"eventDate": "2000-01-01T00:00:00.000Z"
}
],
"handle": "28-LOL",
"ldhName": "redemption.lol",
"links": [
{
"href": "https://example.tld/rdap/domain/redemption.lol",
"rel": "self",
"type": "application/rdap+json"
}
],
"nameservers": [
{
"objectClassName": "nameserver",
"handle": "8-ROID",
"ldhName": "ns1.cat.lol",
"links": [
{
"href": "https://example.tld/rdap/nameserver/ns1.cat.lol",
"rel": "self",
"type": "application/rdap+json"
}
],
"remarks": [
{
"description": [
"Summary data only. For complete data, send a specific query for the object."
],
"title": "Incomplete Data",
"type": "object truncated due to unexplainable reasons"
}
]
}
],
"secureDNS": {
"delegationSigned": false,
"zoneSigned": true
},
"status": [
"pending delete",
"redemption period"
]
}

View File

@@ -0,0 +1,161 @@
{
"rdapConformance": [
"rdap_level_0",
"icann_rdap_response_profile_0",
"icann_rdap_technical_implementation_guide_0"
],
"objectClassName": "domain",
"entities": [
{
"objectClassName": "entity",
"handle": "1",
"links": [
{
"href": "https://example.tld/rdap/entity/1",
"rel": "self",
"type": "application/rdap+json"
}
],
"publicIds": [
{
"identifier": "1",
"type": "IANA Registrar ID"
}
],
"remarks": [
{
"description": [
"Summary data only. For complete data, send a specific query for the object."
],
"title": "Incomplete Data",
"type": "object truncated due to unexplainable reasons"
}
],
"roles": [
"registrar"
],
"vcardArray": [
"vcard",
[
[
"version",
{},
"text",
"4.0"
],
[
"fn",
{},
"text",
"The Registrar"
]
]
]
},
{
"objectClassName": "entity",
"handle": "",
"remarks": [
{
"description": [
"Some of the data in this object has been removed.",
"Contact personal data is visible only to the owning registrar."
],
"links": [
{
"href": "https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel": "alternate",
"type": "text/html"
}
],
"title": "REDACTED FOR PRIVACY",
"type": "object redacted due to authorization"
},
{
"description": [
"Please query the RDDS service of the Registrar of Record identifies in this output for information on how to contact the Registrant of the queried domain name."
],
"title": "EMAIL REDACTED FOR PRIVACY",
"type": "object redacted due to authorization"
}
],
"roles": [
"administrative",
"technical",
"registrant"
],
"vcardArray": [
"vcard",
[
[
"version",
{},
"text",
"4.0"
],
[
"fn",
{},
"text",
""
]
]
]
}
],
"events": [
{
"eventAction": "registration",
"eventActor": "TheRegistrar",
"eventDate": "1999-07-01T00:00:00.000Z"
},
{
"eventAction": "expiration",
"eventDate": "2001-01-01T00:00:00.000Z"
},
{
"eventAction": "last update of RDAP database",
"eventDate": "2000-01-01T00:00:00.000Z"
}
],
"handle": "28-LOL",
"ldhName": "transfer.lol",
"links": [
{
"href": "https://example.tld/rdap/domain/transfer.lol",
"rel": "self",
"type": "application/rdap+json"
}
],
"nameservers": [
{
"objectClassName": "nameserver",
"handle": "8-ROID",
"ldhName": "ns1.cat.lol",
"links": [
{
"href": "https://example.tld/rdap/nameserver/ns1.cat.lol",
"rel": "self",
"type": "application/rdap+json"
}
],
"remarks": [
{
"description": [
"Summary data only. For complete data, send a specific query for the object."
],
"title": "Incomplete Data",
"type": "object truncated due to unexplainable reasons"
}
]
}
],
"secureDNS": {
"delegationSigned": false,
"zoneSigned": true
},
"status": [
"active",
"transfer period"
]
}