RDAP: Add boilerplate entries required by ICANN RDAP Profile

The ICANN RDAP Profile (dated 3 December 2015) requires certain boilerplate entries at the top level of the JSON object. Specifically:

1.4.4. The terms of service of the RDAP service MUST be specified in the
notices object in the topmost JSON object of the response. The notices
object MUST contain a links object [RFC7483]. The links object MUST
contain an URL of the contracted party providing the RDAP service.

1.4.10. An RDAP response MUST contain a remarks member with a description
containing the string “This response conforms to the RDAP Operational
Profile for gTLD Registries and Registrars version 1.0”.

1.5.18. A domain name RDAP response MUST contain a remarks member with
a title “EPP Status Codes”, a description containing the string “For
more information on domain status codes, please visit
https://icann.org/epp” and a links member with the
https://icann.org/epp URL.

1.5.20. A domain name RDAP response MUST contain a remarks member with
a title “Whois Inaccuracy Complaint Form”, a description containing
the string “URL of the ICANN Whois Inaccuracy Complaint Form:
https://www.icann.org/wicf” and a links member with the
https://www.icann.org/wicf URL.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=116389950
This commit is contained in:
mountford 2016-03-04 12:36:00 -08:00 committed by Justine Tunney
parent 363c812d10
commit ab26b288c1
29 changed files with 804 additions and 90 deletions

View file

@ -80,9 +80,20 @@ public abstract class RdapActionBase implements Runnable {
/** Returns the servlet action path; used to extract the search string from the incoming path. */ /** Returns the servlet action path; used to extract the search string from the incoming path. */
abstract String getActionPath(); abstract String getActionPath();
/** Does the actual search and returns an RDAP JSON object. */ /**
abstract ImmutableMap<String, Object> getJsonObjectForResource(String searchString) * Does the actual search and returns an RDAP JSON object.
throws HttpException; *
* @param pathSearchString the search string in the URL path
* @param isHeadRequest whether the returned map will actually be used. HTTP HEAD requests don't
* actually return anything. However, we usually still want to go through the process of
* building a map, to make sure that the request would return a 500 status if it were
* invoked using GET. So this field should usually be ignored, unless there's some
* expensive task required to create the map which will never result in a request failure.
* @param linkBase the base URL for RDAP link structures
* @return A map (probably containing nested maps and lists) with the final JSON response data.
*/
abstract ImmutableMap<String, Object> getJsonObjectForResource(
String pathSearchString, boolean isHeadRequest, String linkBase) throws HttpException;
@Override @Override
public void run() { public void run() {
@ -98,11 +109,13 @@ public abstract class RdapActionBase implements Runnable {
pathProper.startsWith(getActionPath()), pathProper.startsWith(getActionPath()),
"%s doesn't start with %s", pathProper, getActionPath()); "%s doesn't start with %s", pathProper, getActionPath());
ImmutableMap<String, Object> rdapJson = ImmutableMap<String, Object> rdapJson =
getJsonObjectForResource(pathProper.substring(getActionPath().length())); getJsonObjectForResource(
pathProper.substring(getActionPath().length()),
requestMethod == Action.Method.HEAD,
rdapLinkBase);
response.setStatus(SC_OK); response.setStatus(SC_OK);
if (requestMethod != Action.Method.HEAD) { if (requestMethod != Action.Method.HEAD) {
response.setPayload( response.setPayload(JSONValue.toJSONString(rdapJson));
JSONValue.toJSONString(RdapJsonFormatter.makeFinalRdapJson(rdapJson)));
} }
response.setContentType(MediaType.create("application", "rdap+json")); response.setContentType(MediaType.create("application", "rdap+json"));
} catch (HttpException e) { } catch (HttpException e) {

View file

@ -48,8 +48,8 @@ public class RdapAutnumAction extends RdapActionBase {
} }
@Override @Override
public ImmutableMap<String, Object> getJsonObjectForResource(String pathSearchString) public ImmutableMap<String, Object> getJsonObjectForResource(
throws HttpException { String pathSearchString, boolean isHeadRequest, String linkBase) throws HttpException {
throw new NotImplementedException("Domain Name Registry information only"); throw new NotImplementedException("Domain Name Registry information only");
} }
} }

View file

@ -49,8 +49,8 @@ public class RdapDomainAction extends RdapActionBase {
} }
@Override @Override
public ImmutableMap<String, Object> getJsonObjectForResource(String pathSearchString) public ImmutableMap<String, Object> getJsonObjectForResource(
throws HttpException { String pathSearchString, boolean isHeadRequest, String linkBase) throws HttpException {
pathSearchString = canonicalizeName(pathSearchString); pathSearchString = canonicalizeName(pathSearchString);
validateDomainName(pathSearchString); validateDomainName(pathSearchString);
// The query string is not used; the RDAP syntax is /rdap/domain/mydomain.com. // The query string is not used; the RDAP syntax is /rdap/domain/mydomain.com.
@ -59,6 +59,7 @@ public class RdapDomainAction extends RdapActionBase {
if (domainResource == null) { if (domainResource == null) {
throw new NotFoundException(pathSearchString + " not found"); throw new NotFoundException(pathSearchString + " not found");
} }
return RdapJsonFormatter.makeRdapJsonForDomain(domainResource, rdapLinkBase, rdapWhoisServer); return RdapJsonFormatter.makeRdapJsonForDomain(
domainResource, true, rdapLinkBase, rdapWhoisServer);
} }
} }

View file

@ -29,6 +29,7 @@ import com.google.common.collect.Iterables;
import com.google.common.primitives.Booleans; import com.google.common.primitives.Booleans;
import com.google.domain.registry.model.domain.DomainResource; import com.google.domain.registry.model.domain.DomainResource;
import com.google.domain.registry.model.host.HostResource; import com.google.domain.registry.model.host.HostResource;
import com.google.domain.registry.rdap.RdapJsonFormatter.BoilerplateType;
import com.google.domain.registry.request.Action; import com.google.domain.registry.request.Action;
import com.google.domain.registry.request.HttpException; import com.google.domain.registry.request.HttpException;
import com.google.domain.registry.request.HttpException.BadRequestException; import com.google.domain.registry.request.HttpException.BadRequestException;
@ -82,8 +83,8 @@ public class RdapDomainSearchAction extends RdapActionBase {
/** Parses the parameters and calls the appropriate search function. */ /** Parses the parameters and calls the appropriate search function. */
@Override @Override
public ImmutableMap<String, Object> public ImmutableMap<String, Object> getJsonObjectForResource(
getJsonObjectForResource(final String pathSearchString) throws HttpException { String pathSearchString, boolean isHeadRequest, String linkBase) throws HttpException {
DateTime now = clock.nowUtc(); DateTime now = clock.nowUtc();
// RDAP syntax example: /rdap/domains?name=exam*.com. // RDAP syntax example: /rdap/domains?name=exam*.com.
// The pathSearchString is not used by search commands. // The pathSearchString is not used by search commands.
@ -122,7 +123,10 @@ public class RdapDomainSearchAction extends RdapActionBase {
if (results.isEmpty()) { if (results.isEmpty()) {
throw new NotFoundException("No domains found"); throw new NotFoundException("No domains found");
} }
return ImmutableMap.<String, Object>of("domainSearchResults", results); ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
builder.put("domainSearchResults", results);
RdapJsonFormatter.addTopLevelEntries(builder, BoilerplateType.DOMAIN, null, rdapLinkBase);
return builder.build();
} }
/** Searches for domains by domain name, returning a JSON array of domain info maps. */ /** Searches for domains by domain name, returning a JSON array of domain info maps. */
@ -136,7 +140,8 @@ public class RdapDomainSearchAction extends RdapActionBase {
return ImmutableList.of(); return ImmutableList.of();
} }
return ImmutableList.of( return ImmutableList.of(
RdapJsonFormatter.makeRdapJsonForDomain(domainResource, rdapLinkBase, rdapWhoisServer)); RdapJsonFormatter.makeRdapJsonForDomain(
domainResource, false, rdapLinkBase, rdapWhoisServer));
// Handle queries with a wildcard. // Handle queries with a wildcard.
} else { } else {
Query<DomainResource> query = ofy().load() Query<DomainResource> query = ofy().load()
@ -153,7 +158,7 @@ public class RdapDomainSearchAction extends RdapActionBase {
if (domainResource.getDeletionTime().isAfter(now)) { if (domainResource.getDeletionTime().isAfter(now)) {
builder.add( builder.add(
RdapJsonFormatter.makeRdapJsonForDomain( RdapJsonFormatter.makeRdapJsonForDomain(
domainResource, rdapLinkBase, rdapWhoisServer)); domainResource, false, rdapLinkBase, rdapWhoisServer));
} }
} }
return builder.build(); return builder.build();
@ -262,7 +267,8 @@ public class RdapDomainSearchAction extends RdapActionBase {
.limit(1000); .limit(1000);
for (DomainResource domainResource : query) { for (DomainResource domainResource : query) {
builder.add( builder.add(
RdapJsonFormatter.makeRdapJsonForDomain(domainResource, rdapLinkBase, rdapWhoisServer)); RdapJsonFormatter.makeRdapJsonForDomain(
domainResource, false, rdapLinkBase, rdapWhoisServer));
} }
} }
return builder.build(); return builder.build();

View file

@ -24,6 +24,7 @@ import com.google.domain.registry.model.contact.ContactResource;
import com.google.domain.registry.model.domain.DesignatedContact; import com.google.domain.registry.model.domain.DesignatedContact;
import com.google.domain.registry.model.registrar.Registrar; import com.google.domain.registry.model.registrar.Registrar;
import com.google.domain.registry.request.Action; import com.google.domain.registry.request.Action;
import com.google.domain.registry.request.HttpException;
import com.google.domain.registry.request.HttpException.BadRequestException; import com.google.domain.registry.request.HttpException.BadRequestException;
import com.google.domain.registry.request.HttpException.NotFoundException; import com.google.domain.registry.request.HttpException.NotFoundException;
import com.google.domain.registry.util.Clock; import com.google.domain.registry.util.Clock;
@ -58,7 +59,8 @@ public class RdapEntityAction extends RdapActionBase {
} }
@Override @Override
public ImmutableMap<String, Object> getJsonObjectForResource(String pathSearchString) { public ImmutableMap<String, Object> getJsonObjectForResource(
String pathSearchString, boolean isHeadRequest, String linkBase) throws HttpException {
// The query string is not used; the RDAP syntax is /rdap/entity/handle (the handle is the roid // The query string is not used; the RDAP syntax is /rdap/entity/handle (the handle is the roid
// for contacts and the client identifier for registrars). Since RDAP's concept of an entity // for contacts and the client identifier for registrars). Since RDAP's concept of an entity
// includes both contacts and registrars, search for one first, then the other. // includes both contacts and registrars, search for one first, then the other.
@ -70,6 +72,7 @@ public class RdapEntityAction extends RdapActionBase {
if ((contactResource != null) && clock.nowUtc().isBefore(contactResource.getDeletionTime())) { if ((contactResource != null) && clock.nowUtc().isBefore(contactResource.getDeletionTime())) {
return RdapJsonFormatter.makeRdapJsonForContact( return RdapJsonFormatter.makeRdapJsonForContact(
contactResource, contactResource,
true,
Optional.<DesignatedContact.Type>absent(), Optional.<DesignatedContact.Type>absent(),
rdapLinkBase, rdapLinkBase,
rdapWhoisServer); rdapWhoisServer);
@ -80,7 +83,8 @@ public class RdapEntityAction extends RdapActionBase {
wasValidKey = true; wasValidKey = true;
Registrar registrar = Registrar.loadByClientId(clientId); Registrar registrar = Registrar.loadByClientId(clientId);
if ((registrar != null) && registrar.isActiveAndPubliclyVisible()) { if ((registrar != null) && registrar.isActiveAndPubliclyVisible()) {
return RdapJsonFormatter.makeRdapJsonForRegistrar(registrar, rdapLinkBase, rdapWhoisServer); return RdapJsonFormatter.makeRdapJsonForRegistrar(
registrar, true, rdapLinkBase, rdapWhoisServer);
} }
} }
throw !wasValidKey throw !wasValidKey

View file

@ -27,6 +27,7 @@ import com.google.domain.registry.config.ConfigModule.Config;
import com.google.domain.registry.model.contact.ContactResource; import com.google.domain.registry.model.contact.ContactResource;
import com.google.domain.registry.model.domain.DesignatedContact; import com.google.domain.registry.model.domain.DesignatedContact;
import com.google.domain.registry.model.registrar.Registrar; import com.google.domain.registry.model.registrar.Registrar;
import com.google.domain.registry.rdap.RdapJsonFormatter.BoilerplateType;
import com.google.domain.registry.request.Action; import com.google.domain.registry.request.Action;
import com.google.domain.registry.request.HttpException; import com.google.domain.registry.request.HttpException;
import com.google.domain.registry.request.HttpException.BadRequestException; import com.google.domain.registry.request.HttpException.BadRequestException;
@ -76,8 +77,8 @@ public class RdapEntitySearchAction extends RdapActionBase {
/** Parses the parameters and calls the appropriate search function. */ /** Parses the parameters and calls the appropriate search function. */
@Override @Override
public ImmutableMap<String, Object> public ImmutableMap<String, Object> getJsonObjectForResource(
getJsonObjectForResource(final String pathSearchString) throws HttpException { String pathSearchString, boolean isHeadRequest, String linkBase) throws HttpException {
// RDAP syntax example: /rdap/entities?fn=Bobby%20Joe*. // RDAP syntax example: /rdap/entities?fn=Bobby%20Joe*.
// The pathSearchString is not used by search commands. // The pathSearchString is not used by search commands.
if (pathSearchString.length() > 0) { if (pathSearchString.length() > 0) {
@ -97,7 +98,10 @@ public class RdapEntitySearchAction extends RdapActionBase {
if (results.isEmpty()) { if (results.isEmpty()) {
throw new NotFoundException("No entities found"); throw new NotFoundException("No entities found");
} }
return ImmutableMap.<String, Object>of("entitySearchResults", results); ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
builder.put("entitySearchResults", results);
RdapJsonFormatter.addTopLevelEntries(builder, BoilerplateType.OTHER, null, rdapLinkBase);
return builder.build();
} }
/** Searches for entities by handle, returning a JSON array of entity info maps. */ /** Searches for entities by handle, returning a JSON array of entity info maps. */
@ -114,13 +118,14 @@ public class RdapEntitySearchAction extends RdapActionBase {
if ((contactResource != null) && contactResource.getDeletionTime().isEqual(END_OF_TIME)) { if ((contactResource != null) && contactResource.getDeletionTime().isEqual(END_OF_TIME)) {
builder.add(RdapJsonFormatter.makeRdapJsonForContact( builder.add(RdapJsonFormatter.makeRdapJsonForContact(
contactResource, contactResource,
false,
Optional.<DesignatedContact.Type>absent(), Optional.<DesignatedContact.Type>absent(),
rdapLinkBase, rdapLinkBase,
rdapWhoisServer)); rdapWhoisServer));
} }
if ((registrar != null) && registrar.isActiveAndPubliclyVisible()) { if ((registrar != null) && registrar.isActiveAndPubliclyVisible()) {
builder.add(RdapJsonFormatter.makeRdapJsonForRegistrar( builder.add(RdapJsonFormatter.makeRdapJsonForRegistrar(
registrar, rdapLinkBase, rdapWhoisServer)); registrar, false, rdapLinkBase, rdapWhoisServer));
} }
return builder.build(); return builder.build();
// Handle queries with a wildcard, but no suffix. For contact resources, the deletion time will // Handle queries with a wildcard, but no suffix. For contact resources, the deletion time will
@ -139,6 +144,7 @@ public class RdapEntitySearchAction extends RdapActionBase {
for (ContactResource contactResource : query) { for (ContactResource contactResource : query) {
builder.add(RdapJsonFormatter.makeRdapJsonForContact( builder.add(RdapJsonFormatter.makeRdapJsonForContact(
contactResource, contactResource,
false,
Optional.<DesignatedContact.Type>absent(), Optional.<DesignatedContact.Type>absent(),
rdapLinkBase, rdapLinkBase,
rdapWhoisServer)); rdapWhoisServer));
@ -150,7 +156,7 @@ public class RdapEntitySearchAction extends RdapActionBase {
rdapResultSetMaxSize)) { rdapResultSetMaxSize)) {
if (registrar.isActiveAndPubliclyVisible()) { if (registrar.isActiveAndPubliclyVisible()) {
builder.add(RdapJsonFormatter.makeRdapJsonForRegistrar( builder.add(RdapJsonFormatter.makeRdapJsonForRegistrar(
registrar, rdapLinkBase, rdapWhoisServer)); registrar, false, rdapLinkBase, rdapWhoisServer));
} }
} }
// In theory, there could be more results than our max size, so limit the size. // In theory, there could be more results than our max size, so limit the size.

View file

@ -19,6 +19,7 @@ import static com.google.domain.registry.request.Action.Method.HEAD;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.domain.registry.rdap.RdapJsonFormatter.BoilerplateType;
import com.google.domain.registry.rdap.RdapJsonFormatter.MakeRdapJsonNoticeParameters; import com.google.domain.registry.rdap.RdapJsonFormatter.MakeRdapJsonNoticeParameters;
import com.google.domain.registry.request.Action; import com.google.domain.registry.request.Action;
import com.google.domain.registry.request.HttpException; import com.google.domain.registry.request.HttpException;
@ -36,6 +37,16 @@ public class RdapHelpAction extends RdapActionBase {
public static final String PATH = "/rdap/help"; public static final String PATH = "/rdap/help";
/**
* Path for the terms of service. The terms of service are also used to create the required
* boilerplate notice, so we make it a publicly visible that we can use elsewhere to reference it.
*/
public static final String TERMS_OF_SERVICE_PATH = "/tos";
/**
* Map from a relative path underneath the RDAP root path to the appropriate
* {@link MakeRdapJsonNoticeParameters} object.
*/
private static final ImmutableMap<String, MakeRdapJsonNoticeParameters> HELP_MAP = private static final ImmutableMap<String, MakeRdapJsonNoticeParameters> HELP_MAP =
ImmutableMap.of( ImmutableMap.of(
"/", "/",
@ -76,7 +87,7 @@ public class RdapHelpAction extends RdapActionBase {
.linkValueSuffix("help/syntax") .linkValueSuffix("help/syntax")
.linkHrefUrlString("https://www.registry.google/about/rdap/syntax.html") .linkHrefUrlString("https://www.registry.google/about/rdap/syntax.html")
.build(), .build(),
"/tos", TERMS_OF_SERVICE_PATH,
MakeRdapJsonNoticeParameters.builder() MakeRdapJsonNoticeParameters.builder()
.title("RDAP Terms of Service") .title("RDAP Terms of Service")
.description(ImmutableList.of( .description(ImmutableList.of(
@ -119,8 +130,21 @@ public class RdapHelpAction extends RdapActionBase {
} }
@Override @Override
public ImmutableMap<String, Object> getJsonObjectForResource(String pathSearchString) public ImmutableMap<String, Object> getJsonObjectForResource(
throws HttpException { String pathSearchString, boolean isHeadRequest, String linkBase) throws HttpException {
// We rely on addTopLevelEntries to notice if we are sending the TOS notice, and not add a
// duplicate boilerplate entry.
ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
RdapJsonFormatter.addTopLevelEntries(
builder,
BoilerplateType.OTHER,
ImmutableList.of(getJsonHelpNotice(pathSearchString, rdapLinkBase)),
rdapLinkBase);
return builder.build();
}
static ImmutableMap<String, Object> getJsonHelpNotice(
String pathSearchString, String rdapLinkBase) {
if (pathSearchString.isEmpty()) { if (pathSearchString.isEmpty()) {
pathSearchString = "/"; pathSearchString = "/";
} }
@ -128,10 +152,8 @@ public class RdapHelpAction extends RdapActionBase {
throw new NotFoundException("no help found for " + pathSearchString); throw new NotFoundException("no help found for " + pathSearchString);
} }
try { try {
return ImmutableMap.of( return RdapJsonFormatter.makeRdapJsonNotice(
"notices", HELP_MAP.get(pathSearchString), rdapLinkBase);
(Object) ImmutableList.of(RdapJsonFormatter.makeRdapJsonNotice(
HELP_MAP.get(pathSearchString), rdapLinkBase)));
} catch (Exception e) { } catch (Exception e) {
throw new InternalServerErrorException("unable to read help for " + pathSearchString); throw new InternalServerErrorException("unable to read help for " + pathSearchString);
} }

View file

@ -0,0 +1,74 @@
// Copyright 2016 Google Inc. 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 com.google.domain.registry.rdap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
/**
* This file contains boilerplate required by the ICANN RDAP Profile.
*
* @see "https://whois.icann.org/sites/default/files/files/gtld-rdap-operational-profile-draft-03dec15-en.pdf"
*/
public class RdapIcannStandardInformation {
/** Required by ICANN RDAP Profile section 1.4.10. */
private static final ImmutableMap<String, Object> CONFORMANCE_REMARK =
ImmutableMap.<String, Object>of(
"description",
ImmutableList.of(
"This response conforms to the RDAP Operational Profile for gTLD Registries and"
+ " Registrars version 1.0"));
/** Required by ICANN RDAP Profile section 1.5.18. */
private static final ImmutableMap<String, Object> DOMAIN_STATUS_CODES_REMARK =
ImmutableMap.<String, Object> of(
"title",
"EPP Status Codes",
"description",
ImmutableList.of(
"For more information on domain status codes, please visit https://icann.org/epp"),
"links",
ImmutableList.of(
ImmutableMap.of(
"value", "https://icann.org/epp",
"rel", "alternate",
"href", "https://icann.org/epp",
"type", "text/html")));
/** Required by ICANN RDAP Profile section 1.5.20. */
private static final ImmutableMap<String, Object> INACCURACY_COMPLAINT_FORM_REMARK =
ImmutableMap.<String, Object> of(
"description",
ImmutableList.of(
"URL of the ICANN Whois Inaccuracy Complaint Form: https://www.icann.org/wicf"),
"links",
ImmutableList.of(
ImmutableMap.of(
"value", "https://www.icann.org/wicf",
"rel", "alternate",
"href", "https://www.icann.org/wicf",
"type", "text/html")));
/** Boilerplate remarks required by domain responses. */
static final ImmutableList<ImmutableMap<String, Object>> domainBoilerplateRemarks =
ImmutableList.of(
CONFORMANCE_REMARK, DOMAIN_STATUS_CODES_REMARK, INACCURACY_COMPLAINT_FORM_REMARK);
/** Boilerplate remarks required by non-domain responses. */
static final ImmutableList<ImmutableMap<String, Object>> nonDomainBoilerplateRemarks =
ImmutableList.of(CONFORMANCE_REMARK);
}

View file

@ -49,8 +49,8 @@ public class RdapIpAction extends RdapActionBase {
} }
@Override @Override
public ImmutableMap<String, Object> getJsonObjectForResource(String pathSearchString) public ImmutableMap<String, Object> getJsonObjectForResource(
throws HttpException { String pathSearchString, boolean isHeadRequest, String linkBase) throws HttpException {
throw new NotImplementedException("Domain Name Registry information only"); throw new NotImplementedException("Domain Name Registry information only");
} }
} }

View file

@ -72,8 +72,20 @@ import javax.annotation.Nullable;
*/ */
public class RdapJsonFormatter { public class RdapJsonFormatter {
/**
* What type of boilerplate notices are required for the RDAP JSON messages? The ICANN RDAP
* Profile specifies that, for instance, domain name responses should include a remark about
* domain status codes. So we need to know when to include such boilerplate.
*/
public enum BoilerplateType {
DOMAIN,
OTHER
}
private static final String RDAP_CONFORMANCE_LEVEL = "rdap_level_0"; private static final String RDAP_CONFORMANCE_LEVEL = "rdap_level_0";
private static final String VCARD_VERSION_NUMBER = "4.0"; private static final String VCARD_VERSION_NUMBER = "4.0";
static final String NOTICES = "notices";
private static final String REMARKS = "remarks";
/** Status values specified in RFC 7483 10.2.2. */ /** Status values specified in RFC 7483 10.2.2. */
private enum RdapStatus { private enum RdapStatus {
@ -183,19 +195,45 @@ public class RdapJsonFormatter {
}}); }});
/** /**
* Takes an object returned by one of the other methods, and creates a final JSON object suitable * Adds the required top-level boilerplate. RFC 7483 specifies that the top-level object should
* for conversion and transmission. This involves adding one top-level entry, since RFC 7483 * include an entry indicating the conformance level. The ICANN RDAP Profile document (dated 3
* specifies that the top-level object should include an entry indicating the conformance level. * December 2015) mandates several additional entries, in sections 1.4.4, 1.4.10, 1.5.18 and
* 1.5.20. Note that this method will only work if there are no object-specific remarks already in
* the JSON object being built. If there are, the boilerplate must be merged in.
* *
* @param rdapJson an RDAP JSON object created by one of the other methods * @param builder a builder for a JSON map object
* @return an RDAP JSON object with same info as the input, with additional top-level fields * @param boilerplateType type of boilerplate to be added; the ICANN RDAP Profile document
* mandates extra boilerplate for domain objects
* @param notices a list of notices to be inserted before the boilerplate notices. If the TOS
* notice is in this list, the method avoids adding a second copy.
* @param rdapLinkBase the base for link URLs
*/ */
public static ImmutableMap<String, Object> makeFinalRdapJson( static void addTopLevelEntries(
ImmutableMap<String, Object> rdapJson) { ImmutableMap.Builder<String, Object> builder,
ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>(); BoilerplateType boilerplateType,
builder.putAll(rdapJson); @Nullable Iterable<ImmutableMap<String, Object>> notices,
String rdapLinkBase) {
builder.put("rdapConformance", CONFORMANCE_LIST); builder.put("rdapConformance", CONFORMANCE_LIST);
return builder.build(); ImmutableList.Builder<ImmutableMap<String, Object>> noticesBuilder = ImmutableList.builder();
ImmutableMap<String, Object> tosNotice =
RdapHelpAction.getJsonHelpNotice(RdapHelpAction.TERMS_OF_SERVICE_PATH, rdapLinkBase);
boolean tosNoticeFound = false;
if (notices != null) {
noticesBuilder.addAll(notices);
for (ImmutableMap<String, Object> notice : notices) {
if (notice.equals(tosNotice)) {
tosNoticeFound = true;
break;
}
}
}
if (!tosNoticeFound) {
noticesBuilder.add(tosNotice);
}
builder.put(NOTICES, noticesBuilder.build());
builder.put(REMARKS, (boilerplateType == BoilerplateType.DOMAIN)
? RdapIcannStandardInformation.domainBoilerplateRemarks
: RdapIcannStandardInformation.nonDomainBoilerplateRemarks);
} }
/** AutoValue class to build parameters to {@link #makeRdapJsonNotice}. */ /** AutoValue class to build parameters to {@link #makeRdapJsonNotice}. */
@ -225,7 +263,7 @@ public class RdapJsonFormatter {
/** /**
* Creates a JSON object containing a notice or remark object, as defined by RFC 7483 section 4.3. * Creates a JSON object containing a notice or remark object, as defined by RFC 7483 section 4.3.
* The object should then be inserted into a "notices" or "remarks" array. The builder fields are: * The object should then be inserted into a notices or remarks array. The builder fields are:
* *
* <p>title: the title of the notice; if null, the notice will have no title * <p>title: the title of the notice; if null, the notice will have no title
* *
@ -251,8 +289,8 @@ public class RdapJsonFormatter {
* @see <a href="https://tools.ietf.org/html/rfc7483"> * @see <a href="https://tools.ietf.org/html/rfc7483">
* RFC 7483: JSON Responses for the Registration Data Access Protocol (RDAP)</a> * RFC 7483: JSON Responses for the Registration Data Access Protocol (RDAP)</a>
*/ */
public static ImmutableMap<String, Object> static ImmutableMap<String, Object> makeRdapJsonNotice(
makeRdapJsonNotice(MakeRdapJsonNoticeParameters parameters, @Nullable String linkBase) { MakeRdapJsonNoticeParameters parameters, @Nullable String linkBase) {
ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>(); ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
if (parameters.title() != null) { if (parameters.title() != null) {
builder.put("title", parameters.title()); builder.put("title", parameters.title());
@ -293,8 +331,11 @@ public class RdapJsonFormatter {
* @param whoisServer the fully-qualified domain name of the WHOIS server to be listed in the * @param whoisServer the fully-qualified domain name of the WHOIS server to be listed in the
* port43 field; if null, port43 is not added to the object * port43 field; if null, port43 is not added to the object
*/ */
public static ImmutableMap<String, Object> makeRdapJsonForDomain( static ImmutableMap<String, Object> makeRdapJsonForDomain(
DomainResource domainResource, @Nullable String linkBase, @Nullable String whoisServer) { DomainResource domainResource,
boolean isTopLevel,
@Nullable String linkBase,
@Nullable String whoisServer) {
// Kick off the database loads of the nameservers that we will need. // Kick off the database loads of the nameservers that we will need.
Set<Ref<HostResource>> hostRefs = new LinkedHashSet<>(); Set<Ref<HostResource>> hostRefs = new LinkedHashSet<>();
for (ReferenceUnion<HostResource> hostReference : domainResource.getNameservers()) { for (ReferenceUnion<HostResource> hostReference : domainResource.getNameservers()) {
@ -328,7 +369,7 @@ public class RdapJsonFormatter {
ImmutableList.Builder<Object> nsBuilder = new ImmutableList.Builder<>(); ImmutableList.Builder<Object> nsBuilder = new ImmutableList.Builder<>();
for (HostResource hostResource for (HostResource hostResource
: HOST_RESOURCE_ORDERING.immutableSortedCopy(loadedHosts.values())) { : HOST_RESOURCE_ORDERING.immutableSortedCopy(loadedHosts.values())) {
nsBuilder.add(makeRdapJsonForHost(hostResource, linkBase, null)); nsBuilder.add(makeRdapJsonForHost(hostResource, false, linkBase, null));
} }
ImmutableList<Object> ns = nsBuilder.build(); ImmutableList<Object> ns = nsBuilder.build();
if (!ns.isEmpty()) { if (!ns.isEmpty()) {
@ -341,7 +382,7 @@ public class RdapJsonFormatter {
ContactResource loadedContact = ContactResource loadedContact =
loadedContacts.get(designatedContact.getContactId().getLinked().key()); loadedContacts.get(designatedContact.getContactId().getLinked().key());
entitiesBuilder.add(makeRdapJsonForContact( entitiesBuilder.add(makeRdapJsonForContact(
loadedContact, Optional.of(designatedContact.getType()), linkBase, null)); loadedContact, false, Optional.of(designatedContact.getType()), linkBase, null));
} }
ImmutableList<Object> entities = entitiesBuilder.build(); ImmutableList<Object> entities = entitiesBuilder.build();
if (!entities.isEmpty()) { if (!entities.isEmpty()) {
@ -350,6 +391,9 @@ public class RdapJsonFormatter {
if (whoisServer != null) { if (whoisServer != null) {
builder.put("port43", whoisServer); builder.put("port43", whoisServer);
} }
if (isTopLevel) {
addTopLevelEntries(builder, BoilerplateType.DOMAIN, null, linkBase);
}
return builder.build(); return builder.build();
} }
@ -361,8 +405,11 @@ public class RdapJsonFormatter {
* @param whoisServer the fully-qualified domain name of the WHOIS server to be listed in the * @param whoisServer the fully-qualified domain name of the WHOIS server to be listed in the
* port43 field; if null, port43 is not added to the object * port43 field; if null, port43 is not added to the object
*/ */
public static ImmutableMap<String, Object> makeRdapJsonForHost( static ImmutableMap<String, Object> makeRdapJsonForHost(
HostResource hostResource, @Nullable String linkBase, @Nullable String whoisServer) { HostResource hostResource,
boolean isTopLevel,
@Nullable String linkBase,
@Nullable String whoisServer) {
ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>(); ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
builder.put("objectClassName", "nameserver"); builder.put("objectClassName", "nameserver");
builder.put("handle", hostResource.getRepoId()); builder.put("handle", hostResource.getRepoId());
@ -403,6 +450,9 @@ public class RdapJsonFormatter {
if (whoisServer != null) { if (whoisServer != null) {
builder.put("port43", whoisServer); builder.put("port43", whoisServer);
} }
if (isTopLevel) {
addTopLevelEntries(builder, BoilerplateType.OTHER, null, linkBase);
}
return builder.build(); return builder.build();
} }
@ -415,8 +465,9 @@ public class RdapJsonFormatter {
* @param whoisServer the fully-qualified domain name of the WHOIS server to be listed in the * @param whoisServer the fully-qualified domain name of the WHOIS server to be listed in the
* port43 field; if null, port43 is not added to the object * port43 field; if null, port43 is not added to the object
*/ */
public static ImmutableMap<String, Object> makeRdapJsonForContact( static ImmutableMap<String, Object> makeRdapJsonForContact(
ContactResource contactResource, ContactResource contactResource,
boolean isTopLevel,
Optional<DesignatedContact.Type> contactType, Optional<DesignatedContact.Type> contactType,
@Nullable String linkBase, @Nullable String linkBase,
@Nullable String whoisServer) { @Nullable String whoisServer) {
@ -464,6 +515,9 @@ public class RdapJsonFormatter {
if (whoisServer != null) { if (whoisServer != null) {
builder.put("port43", whoisServer); builder.put("port43", whoisServer);
} }
if (isTopLevel) {
addTopLevelEntries(builder, BoilerplateType.OTHER, null, linkBase);
}
return builder.build(); return builder.build();
} }
@ -475,8 +529,11 @@ public class RdapJsonFormatter {
* @param whoisServer the fully-qualified domain name of the WHOIS server to be listed in the * @param whoisServer the fully-qualified domain name of the WHOIS server to be listed in the
* port43 field; if null, port43 is not added to the object * port43 field; if null, port43 is not added to the object
*/ */
public static ImmutableMap<String, Object> makeRdapJsonForRegistrar( static ImmutableMap<String, Object> makeRdapJsonForRegistrar(
Registrar registrar, @Nullable String linkBase, @Nullable String whoisServer) { Registrar registrar,
boolean isTopLevel,
@Nullable String linkBase,
@Nullable String whoisServer) {
ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>(); ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
builder.put("objectClassName", "entity"); builder.put("objectClassName", "entity");
builder.put("handle", registrar.getClientIdentifier()); builder.put("handle", registrar.getClientIdentifier());
@ -534,6 +591,9 @@ public class RdapJsonFormatter {
if (whoisServer != null) { if (whoisServer != null) {
builder.put("port43", whoisServer); builder.put("port43", whoisServer);
} }
if (isTopLevel) {
addTopLevelEntries(builder, BoilerplateType.OTHER, null, linkBase);
}
return builder.build(); return builder.build();
} }
@ -544,7 +604,7 @@ public class RdapJsonFormatter {
* @param whoisServer the fully-qualified domain name of the WHOIS server to be listed in the * @param whoisServer the fully-qualified domain name of the WHOIS server to be listed in the
* port43 field; if null, port43 is not added to the object * port43 field; if null, port43 is not added to the object
*/ */
public static ImmutableMap<String, Object> makeRdapJsonForRegistrarContact( static ImmutableMap<String, Object> makeRdapJsonForRegistrarContact(
RegistrarContact registrarContact, @Nullable String whoisServer) { RegistrarContact registrarContact, @Nullable String whoisServer) {
ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>(); ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
builder.put("objectClassName", "entity"); builder.put("objectClassName", "entity");
@ -705,7 +765,7 @@ public class RdapJsonFormatter {
* @see <a href="https://tools.ietf.org/html/rfc7483"> * @see <a href="https://tools.ietf.org/html/rfc7483">
* RFC 7483: JSON Responses for the Registration Data Access Protocol (RDAP)</a> * RFC 7483: JSON Responses for the Registration Data Access Protocol (RDAP)</a>
*/ */
public static ImmutableMap<String, Object> makeError( static ImmutableMap<String, Object> makeError(
int status, String title, String description) { int status, String title, String description) {
return ImmutableMap.<String, Object>of( return ImmutableMap.<String, Object>of(
"rdapConformance", CONFORMANCE_LIST, "rdapConformance", CONFORMANCE_LIST,

View file

@ -50,7 +50,7 @@ public class RdapNameserverAction extends RdapActionBase {
@Override @Override
public ImmutableMap<String, Object> getJsonObjectForResource( public ImmutableMap<String, Object> getJsonObjectForResource(
String pathSearchString) throws HttpException { String pathSearchString, boolean isHeadRequest, String linkBase) throws HttpException {
pathSearchString = canonicalizeName(pathSearchString); pathSearchString = canonicalizeName(pathSearchString);
// The RDAP syntax is /rdap/nameserver/ns1.mydomain.com. // The RDAP syntax is /rdap/nameserver/ns1.mydomain.com.
validateDomainName(pathSearchString); validateDomainName(pathSearchString);
@ -59,6 +59,6 @@ public class RdapNameserverAction extends RdapActionBase {
if (hostResource == null) { if (hostResource == null) {
throw new NotFoundException(pathSearchString + " not found"); throw new NotFoundException(pathSearchString + " not found");
} }
return RdapJsonFormatter.makeRdapJsonForHost(hostResource, rdapLinkBase, rdapWhoisServer); return RdapJsonFormatter.makeRdapJsonForHost(hostResource, true, rdapLinkBase, rdapWhoisServer);
} }
} }

View file

@ -28,6 +28,7 @@ import com.google.common.primitives.Booleans;
import com.google.domain.registry.config.ConfigModule.Config; import com.google.domain.registry.config.ConfigModule.Config;
import com.google.domain.registry.model.domain.DomainResource; import com.google.domain.registry.model.domain.DomainResource;
import com.google.domain.registry.model.host.HostResource; import com.google.domain.registry.model.host.HostResource;
import com.google.domain.registry.rdap.RdapJsonFormatter.BoilerplateType;
import com.google.domain.registry.request.Action; import com.google.domain.registry.request.Action;
import com.google.domain.registry.request.HttpException; import com.google.domain.registry.request.HttpException;
import com.google.domain.registry.request.HttpException.BadRequestException; import com.google.domain.registry.request.HttpException.BadRequestException;
@ -77,8 +78,8 @@ public class RdapNameserverSearchAction extends RdapActionBase {
/** Parses the parameters and calls the appropriate search function. */ /** Parses the parameters and calls the appropriate search function. */
@Override @Override
public ImmutableMap<String, Object> public ImmutableMap<String, Object> getJsonObjectForResource(
getJsonObjectForResource(final String pathSearchString) throws HttpException { String pathSearchString, boolean isHeadRequest, String linkBase) throws HttpException {
DateTime now = clock.nowUtc(); DateTime now = clock.nowUtc();
// RDAP syntax example: /rdap/nameservers?name=ns*.example.com. // RDAP syntax example: /rdap/nameservers?name=ns*.example.com.
// The pathSearchString is not used by search commands. // The pathSearchString is not used by search commands.
@ -105,7 +106,10 @@ public class RdapNameserverSearchAction extends RdapActionBase {
if (results.isEmpty()) { if (results.isEmpty()) {
throw new NotFoundException("No nameservers found"); throw new NotFoundException("No nameservers found");
} }
return ImmutableMap.<String, Object>of("nameserverSearchResults", results); ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
builder.put("nameserverSearchResults", results);
RdapJsonFormatter.addTopLevelEntries(builder, BoilerplateType.OTHER, null, rdapLinkBase);
return builder.build();
} }
/** Searches for nameservers by name, returning a JSON array of nameserver info maps. */ /** Searches for nameservers by name, returning a JSON array of nameserver info maps. */
@ -120,7 +124,8 @@ public class RdapNameserverSearchAction extends RdapActionBase {
throw new NotFoundException("No nameservers found"); throw new NotFoundException("No nameservers found");
} }
return ImmutableList.of( return ImmutableList.of(
RdapJsonFormatter.makeRdapJsonForHost(hostResource, rdapLinkBase, rdapWhoisServer)); RdapJsonFormatter.makeRdapJsonForHost(
hostResource, false, rdapLinkBase, rdapWhoisServer));
// Handle queries with a wildcard, but no suffix. There are no pending deletes for hosts, so we // Handle queries with a wildcard, but no suffix. There are no pending deletes for hosts, so we
// can call queryUndeleted. // can call queryUndeleted.
} else if (partialStringQuery.getSuffix() == null) { } else if (partialStringQuery.getSuffix() == null) {
@ -131,7 +136,8 @@ public class RdapNameserverSearchAction extends RdapActionBase {
ImmutableList.Builder<ImmutableMap<String, Object>> builder = new ImmutableList.Builder<>(); ImmutableList.Builder<ImmutableMap<String, Object>> builder = new ImmutableList.Builder<>();
for (HostResource hostResource : query) { for (HostResource hostResource : query) {
builder.add( builder.add(
RdapJsonFormatter.makeRdapJsonForHost(hostResource, rdapLinkBase, rdapWhoisServer)); RdapJsonFormatter.makeRdapJsonForHost(
hostResource, false, rdapLinkBase, rdapWhoisServer));
} }
return builder.build(); return builder.build();
// Handle queries with a wildcard and a suffix. In this case, it is more efficient to do things // Handle queries with a wildcard and a suffix. In this case, it is more efficient to do things
@ -151,7 +157,8 @@ public class RdapNameserverSearchAction extends RdapActionBase {
HostResource hostResource = loadByUniqueId(HostResource.class, fqhn, clock.nowUtc()); HostResource hostResource = loadByUniqueId(HostResource.class, fqhn, clock.nowUtc());
if (hostResource != null) { if (hostResource != null) {
builder.add( builder.add(
RdapJsonFormatter.makeRdapJsonForHost(hostResource, rdapLinkBase, rdapWhoisServer)); RdapJsonFormatter.makeRdapJsonForHost(
hostResource, false, rdapLinkBase, rdapWhoisServer));
} }
} }
} }
@ -174,7 +181,8 @@ public class RdapNameserverSearchAction extends RdapActionBase {
ImmutableList.Builder<ImmutableMap<String, Object>> builder = new ImmutableList.Builder<>(); ImmutableList.Builder<ImmutableMap<String, Object>> builder = new ImmutableList.Builder<>();
for (HostResource hostResource : query) { for (HostResource hostResource : query) {
builder.add( builder.add(
RdapJsonFormatter.makeRdapJsonForHost(hostResource, rdapLinkBase, rdapWhoisServer)); RdapJsonFormatter.makeRdapJsonForHost(
hostResource, false, rdapLinkBase, rdapWhoisServer));
} }
return builder.build(); return builder.build();
} }

View file

@ -19,9 +19,12 @@ import static com.google.common.truth.Truth.assertThat;
import static com.google.domain.registry.request.Action.Method.GET; import static com.google.domain.registry.request.Action.Method.GET;
import static com.google.domain.registry.request.Action.Method.HEAD; import static com.google.domain.registry.request.Action.Method.HEAD;
import static com.google.domain.registry.testing.DatastoreHelper.createTld; import static com.google.domain.registry.testing.DatastoreHelper.createTld;
import static com.google.domain.registry.testing.TestDataHelper.loadFileWithSubstitutions;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.domain.registry.model.ofy.Ofy; import com.google.domain.registry.model.ofy.Ofy;
import com.google.domain.registry.rdap.RdapJsonFormatter.BoilerplateType;
import com.google.domain.registry.request.HttpException;
import com.google.domain.registry.testing.AppEngineRule; import com.google.domain.registry.testing.AppEngineRule;
import com.google.domain.registry.testing.FakeClock; import com.google.domain.registry.testing.FakeClock;
import com.google.domain.registry.testing.FakeResponse; import com.google.domain.registry.testing.FakeResponse;
@ -68,14 +71,22 @@ public class RdapActionBaseTest {
} }
@Override @Override
public ImmutableMap<String, Object> getJsonObjectForResource(String searchString) { public ImmutableMap<String, Object> getJsonObjectForResource(
if (searchString.equals("IllegalArgumentException")) { String pathSearchString, boolean isHeadRequest, String linkBase) throws HttpException {
if (pathSearchString.equals("IllegalArgumentException")) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
if (searchString.equals("RuntimeException")) { if (pathSearchString.equals("RuntimeException")) {
throw new RuntimeException(); throw new RuntimeException();
} }
return ImmutableMap.<String, Object>of("key", "value"); ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
builder.put("key", "value");
RdapJsonFormatter.addTopLevelEntries(
builder,
BoilerplateType.OTHER,
null,
"http://myserver.google.com/");
return builder.build();
} }
} }
@ -92,6 +103,7 @@ public class RdapActionBaseTest {
private Object generateActualJson(String domainName) { private Object generateActualJson(String domainName) {
action.requestPath = RdapTestAction.PATH + domainName; action.requestPath = RdapTestAction.PATH + domainName;
action.requestMethod = GET; action.requestMethod = GET;
action.rdapLinkBase = "http://myserver.google.com/";
action.run(); action.run();
return JSONValue.parse(response.getPayload()); return JSONValue.parse(response.getPayload());
} }
@ -99,6 +111,7 @@ public class RdapActionBaseTest {
private String generateHeadPayload(String domainName) { private String generateHeadPayload(String domainName) {
action.requestPath = RdapTestAction.PATH + domainName; action.requestPath = RdapTestAction.PATH + domainName;
action.requestMethod = HEAD; action.requestMethod = HEAD;
action.rdapLinkBase = "http://myserver.google.com/";
action.run(); action.run();
return response.getPayload(); return response.getPayload();
} }
@ -124,7 +137,7 @@ public class RdapActionBaseTest {
@Test @Test
public void testValidName_works() throws Exception { public void testValidName_works() throws Exception {
assertThat(generateActualJson("no.thing")).isEqualTo(JSONValue.parse( assertThat(generateActualJson("no.thing")).isEqualTo(JSONValue.parse(
"{\"rdapConformance\":[\"rdap_level_0\"], \"key\":\"value\"}")); loadFileWithSubstitutions(this.getClass(), "rdapjson_toplevel.json", null)));
assertThat(response.getStatus()).isEqualTo(200); assertThat(response.getStatus()).isEqualTo(200);
} }

View file

@ -164,6 +164,12 @@ public class RdapDomainActionTest {
if (!map.containsKey("rdapConformance")) { if (!map.containsKey("rdapConformance")) {
builder.put("rdapConformance", ImmutableList.of("rdap_level_0")); builder.put("rdapConformance", ImmutableList.of("rdap_level_0"));
} }
if (!map.containsKey("notices")) {
RdapTestHelper.addTermsOfServiceNotice(builder, "https://example.com/rdap/");
}
if (!map.containsKey("remarks")) {
RdapTestHelper.addDomainBoilerplateRemarks(builder);
}
if (!map.containsKey("port43")) { if (!map.containsKey("port43")) {
builder.put("port43", "whois.example.com"); builder.put("port43", "whois.example.com");
} }

View file

@ -210,6 +210,8 @@ public class RdapDomainSearchActionTest {
ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>(); ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
builder.put("domainSearchResults", ImmutableList.of(obj)); builder.put("domainSearchResults", ImmutableList.of(obj));
builder.put("rdapConformance", ImmutableList.of("rdap_level_0")); builder.put("rdapConformance", ImmutableList.of("rdap_level_0"));
RdapTestHelper.addTermsOfServiceNotice(builder, "https://example.com/rdap/");
RdapTestHelper.addDomainBoilerplateRemarks(builder);
return builder.build(); return builder.build();
} }

View file

@ -181,6 +181,12 @@ public class RdapEntityActionTest {
if (!map.containsKey("port43")) { if (!map.containsKey("port43")) {
builder.put("port43", "whois.example.tld"); builder.put("port43", "whois.example.tld");
} }
if (!map.containsKey("notices")) {
RdapTestHelper.addTermsOfServiceNotice(builder, "https://example.com/rdap/");
}
if (!map.containsKey("remarks")) {
RdapTestHelper.addNonDomainBoilerplateRemarks(builder);
}
obj = builder.build(); obj = builder.build();
} }
return obj; return obj;

View file

@ -166,6 +166,8 @@ public class RdapEntitySearchActionTest {
ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>(); ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
builder.put("entitySearchResults", ImmutableList.of(obj)); builder.put("entitySearchResults", ImmutableList.of(obj));
builder.put("rdapConformance", ImmutableList.of("rdap_level_0")); builder.put("rdapConformance", ImmutableList.of("rdap_level_0"));
RdapTestHelper.addTermsOfServiceNotice(builder, "https://example.com/rdap/");
RdapTestHelper.addNonDomainBoilerplateRemarks(builder);
return builder.build(); return builder.build();
} }

View file

@ -109,7 +109,8 @@ public class RdapHelpActionTest {
@Test @Test
public void testHelpActionTos_works() throws Exception { public void testHelpActionTos_works() throws Exception {
generateActualJson("/tos"); assertThat(generateActualJson("/tos"))
.isEqualTo(generateExpectedJson("", "rdap_help_tos.json"));
assertThat(response.getStatus()).isEqualTo(200); assertThat(response.getStatus()).isEqualTo(200);
} }
} }

View file

@ -187,32 +187,36 @@ public class RdapJsonFormatterTest {
@Test @Test
public void testRegistrar() throws Exception { public void testRegistrar() throws Exception {
assertThat(RdapJsonFormatter.makeRdapJsonForRegistrar(registrar, LINK_BASE, WHOIS_SERVER)) assertThat(
.isEqualTo(loadJson("rdapjson_registrar.json")); RdapJsonFormatter.makeRdapJsonForRegistrar(registrar, false, LINK_BASE, WHOIS_SERVER))
.isEqualTo(loadJson("rdapjson_registrar.json"));
} }
@Test @Test
public void testHost_ipv4() throws Exception { public void testHost_ipv4() throws Exception {
assertThat(RdapJsonFormatter.makeRdapJsonForHost(hostResourceIpv4, LINK_BASE, WHOIS_SERVER)) assertThat(
.isEqualTo(loadJson("rdapjson_host_ipv4.json")); RdapJsonFormatter.makeRdapJsonForHost(hostResourceIpv4, false, LINK_BASE, WHOIS_SERVER))
.isEqualTo(loadJson("rdapjson_host_ipv4.json"));
} }
@Test @Test
public void testHost_ipv6() throws Exception { public void testHost_ipv6() throws Exception {
assertThat(RdapJsonFormatter.makeRdapJsonForHost(hostResourceIpv6, LINK_BASE, WHOIS_SERVER)) assertThat(
.isEqualTo(loadJson("rdapjson_host_ipv6.json")); RdapJsonFormatter.makeRdapJsonForHost(hostResourceIpv6, false, LINK_BASE, WHOIS_SERVER))
.isEqualTo(loadJson("rdapjson_host_ipv6.json"));
} }
@Test @Test
public void testHost_both() throws Exception { public void testHost_both() throws Exception {
assertThat(RdapJsonFormatter.makeRdapJsonForHost(hostResourceBoth, LINK_BASE, WHOIS_SERVER)) assertThat(
.isEqualTo(loadJson("rdapjson_host_both.json")); RdapJsonFormatter.makeRdapJsonForHost(hostResourceBoth, false, LINK_BASE, WHOIS_SERVER))
.isEqualTo(loadJson("rdapjson_host_both.json"));
} }
@Test @Test
public void testHost_noAddresses() throws Exception { public void testHost_noAddresses() throws Exception {
assertThat(RdapJsonFormatter.makeRdapJsonForHost( assertThat(RdapJsonFormatter.makeRdapJsonForHost(
hostResourceNoAddresses, LINK_BASE, WHOIS_SERVER)) hostResourceNoAddresses, false, LINK_BASE, WHOIS_SERVER))
.isEqualTo(loadJson("rdapjson_host_no_addresses.json")); .isEqualTo(loadJson("rdapjson_host_no_addresses.json"));
} }
@ -221,6 +225,7 @@ public class RdapJsonFormatterTest {
assertThat( assertThat(
RdapJsonFormatter.makeRdapJsonForContact( RdapJsonFormatter.makeRdapJsonForContact(
contactResourceRegistrant, contactResourceRegistrant,
false,
Optional.of(DesignatedContact.Type.REGISTRANT), Optional.of(DesignatedContact.Type.REGISTRANT),
LINK_BASE, LINK_BASE,
WHOIS_SERVER)) WHOIS_SERVER))
@ -232,6 +237,7 @@ public class RdapJsonFormatterTest {
assertThat( assertThat(
RdapJsonFormatter.makeRdapJsonForContact( RdapJsonFormatter.makeRdapJsonForContact(
contactResourceRegistrant, contactResourceRegistrant,
false,
Optional.of(DesignatedContact.Type.REGISTRANT), Optional.of(DesignatedContact.Type.REGISTRANT),
LINK_BASE_NO_TRAILING_SLASH, LINK_BASE_NO_TRAILING_SLASH,
WHOIS_SERVER)) WHOIS_SERVER))
@ -243,6 +249,7 @@ public class RdapJsonFormatterTest {
assertThat( assertThat(
RdapJsonFormatter.makeRdapJsonForContact( RdapJsonFormatter.makeRdapJsonForContact(
contactResourceRegistrant, contactResourceRegistrant,
false,
Optional.of(DesignatedContact.Type.REGISTRANT), Optional.of(DesignatedContact.Type.REGISTRANT),
null, null,
WHOIS_SERVER)) WHOIS_SERVER))
@ -254,6 +261,7 @@ public class RdapJsonFormatterTest {
assertThat( assertThat(
RdapJsonFormatter.makeRdapJsonForContact( RdapJsonFormatter.makeRdapJsonForContact(
contactResourceAdmin, contactResourceAdmin,
false,
Optional.of(DesignatedContact.Type.ADMIN), Optional.of(DesignatedContact.Type.ADMIN),
LINK_BASE, LINK_BASE,
WHOIS_SERVER)) WHOIS_SERVER))
@ -265,6 +273,7 @@ public class RdapJsonFormatterTest {
assertThat( assertThat(
RdapJsonFormatter.makeRdapJsonForContact( RdapJsonFormatter.makeRdapJsonForContact(
contactResourceTech, contactResourceTech,
false,
Optional.of(DesignatedContact.Type.TECH), Optional.of(DesignatedContact.Type.TECH),
LINK_BASE, LINK_BASE,
WHOIS_SERVER)) WHOIS_SERVER))
@ -274,7 +283,8 @@ public class RdapJsonFormatterTest {
@Test @Test
public void testDomain_full() throws Exception { public void testDomain_full() throws Exception {
assertThat( assertThat(
RdapJsonFormatter.makeRdapJsonForDomain(domainResourceFull, LINK_BASE, WHOIS_SERVER)) RdapJsonFormatter.makeRdapJsonForDomain(
domainResourceFull, false, LINK_BASE, WHOIS_SERVER))
.isEqualTo(loadJson("rdapjson_domain_full.json")); .isEqualTo(loadJson("rdapjson_domain_full.json"));
} }
@ -282,7 +292,7 @@ public class RdapJsonFormatterTest {
public void testDomain_noRegistrant() throws Exception { public void testDomain_noRegistrant() throws Exception {
assertThat( assertThat(
RdapJsonFormatter.makeRdapJsonForDomain( RdapJsonFormatter.makeRdapJsonForDomain(
domainResourceNoRegistrant, LINK_BASE, WHOIS_SERVER)) domainResourceNoRegistrant, false, LINK_BASE, WHOIS_SERVER))
.isEqualTo(loadJson("rdapjson_domain_no_registrant.json")); .isEqualTo(loadJson("rdapjson_domain_no_registrant.json"));
} }
@ -290,7 +300,7 @@ public class RdapJsonFormatterTest {
public void testDomain_noContacts() throws Exception { public void testDomain_noContacts() throws Exception {
assertThat( assertThat(
RdapJsonFormatter.makeRdapJsonForDomain( RdapJsonFormatter.makeRdapJsonForDomain(
domainResourceNoContacts, LINK_BASE, WHOIS_SERVER)) domainResourceNoContacts, false, LINK_BASE, WHOIS_SERVER))
.isEqualTo(loadJson("rdapjson_domain_no_contacts.json")); .isEqualTo(loadJson("rdapjson_domain_no_contacts.json"));
} }
@ -298,7 +308,7 @@ public class RdapJsonFormatterTest {
public void testDomain_noNameservers() throws Exception { public void testDomain_noNameservers() throws Exception {
assertThat( assertThat(
RdapJsonFormatter.makeRdapJsonForDomain( RdapJsonFormatter.makeRdapJsonForDomain(
domainResourceNoNameservers, LINK_BASE, WHOIS_SERVER)) domainResourceNoNameservers, false, LINK_BASE, WHOIS_SERVER))
.isEqualTo(loadJson("rdapjson_domain_no_nameservers.json")); .isEqualTo(loadJson("rdapjson_domain_no_nameservers.json"));
} }
@ -375,8 +385,49 @@ public class RdapJsonFormatterTest {
@Test @Test
public void testTopLevel() throws Exception { public void testTopLevel() throws Exception {
assertThat( ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
RdapJsonFormatter.makeFinalRdapJson(ImmutableMap.<String, Object>of("key", "value"))) builder.put("key", "value");
.isEqualTo(loadJson("rdapjson_toplevel.json")); RdapJsonFormatter.addTopLevelEntries(
builder,
RdapJsonFormatter.BoilerplateType.OTHER,
null,
LINK_BASE);
assertThat(builder.build()).isEqualTo(loadJson("rdapjson_toplevel.json"));
}
@Test
public void testTopLevel_withTermsOfService() throws Exception {
ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
builder.put("key", "value");
RdapJsonFormatter.addTopLevelEntries(
builder,
RdapJsonFormatter.BoilerplateType.OTHER,
ImmutableList.of(RdapHelpAction.getJsonHelpNotice("/tos", LINK_BASE)),
LINK_BASE);
assertThat(builder.build()).isEqualTo(loadJson("rdapjson_toplevel.json"));
}
@Test
public void testTopLevel_domain() throws Exception {
ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
builder.put("key", "value");
RdapJsonFormatter.addTopLevelEntries(
builder,
RdapJsonFormatter.BoilerplateType.DOMAIN,
null,
LINK_BASE);
assertThat(builder.build()).isEqualTo(loadJson("rdapjson_toplevel_domain.json"));
}
@Test
public void testTopLevel_domainWithTermsOfService() throws Exception {
ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
builder.put("key", "value");
RdapJsonFormatter.addTopLevelEntries(
builder,
RdapJsonFormatter.BoilerplateType.DOMAIN,
ImmutableList.of(RdapHelpAction.getJsonHelpNotice("/tos", LINK_BASE)),
LINK_BASE);
assertThat(builder.build()).isEqualTo(loadJson("rdapjson_toplevel_domain.json"));
} }
} }

View file

@ -128,6 +128,12 @@ public class RdapNameserverActionTest {
if (!map.containsKey("port43")) { if (!map.containsKey("port43")) {
builder.put("port43", "whois.example.tld"); builder.put("port43", "whois.example.tld");
} }
if (!map.containsKey("notices")) {
RdapTestHelper.addTermsOfServiceNotice(builder, "https://example.tld/rdap/");
}
if (!map.containsKey("remarks")) {
RdapTestHelper.addNonDomainBoilerplateRemarks(builder);
}
obj = builder.build(); obj = builder.build();
} }
return obj; return obj;

View file

@ -177,6 +177,8 @@ public class RdapNameserverSearchActionTest {
ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>(); ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
builder.put("nameserverSearchResults", ImmutableList.of(obj)); builder.put("nameserverSearchResults", ImmutableList.of(obj));
builder.put("rdapConformance", ImmutableList.of("rdap_level_0")); builder.put("rdapConformance", ImmutableList.of("rdap_level_0"));
RdapTestHelper.addTermsOfServiceNotice(builder, "https://example.tld/rdap/");
RdapTestHelper.addNonDomainBoilerplateRemarks(builder);
return builder.build(); return builder.build();
} }

View file

@ -0,0 +1,103 @@
// Copyright 2016 Google Inc. 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 com.google.domain.registry.rdap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
public class RdapTestHelper {
static void addTermsOfServiceNotice(
ImmutableMap.Builder<String, Object> builder, String linkBase) {
builder.put("notices",
ImmutableList.of(
ImmutableMap.of(
"title", "RDAP Terms of Service",
"description", ImmutableList.of(
"By querying our Domain Database, you are agreeing to comply with these terms"
+ " so please read them carefully.",
"Any information provided is 'as is' without any guarantee of accuracy.",
"Please do not misuse the Domain Database. It is intended solely for"
+ " query-based access.",
"Don't use the Domain Database to allow, enable, or otherwise support the"
+ " transmission of mass unsolicited, commercial advertising or"
+ " solicitations.",
"Don't access our Domain Database through the use of high volume, automated"
+ " electronic processes that send queries or data to the systems of"
+ " Charleston Road Registry or any ICANN-accredited registrar.",
"You may only use the information contained in the Domain Database for lawful"
+ " purposes.",
"Do not compile, repackage, disseminate, or otherwise use the information"
+ " contained in the Domain Database in its entirety, or in any substantial"
+ " portion, without our prior written permission.",
"We may retain certain details about queries to our Domain Database for the"
+ " purposes of detecting and preventing misuse.",
"We reserve the right to restrict or deny your access to the database if we"
+ " suspect that you have failed to comply with these terms.",
"We reserve the right to modify this agreement at any time."),
"links", ImmutableList.of(
ImmutableMap.of(
"value", linkBase + "help/tos",
"rel", "alternate",
"href", "https://www.registry.google/about/rdap/tos.html",
"type", "text/html")))));
}
static void addNonDomainBoilerplateRemarks(ImmutableMap.Builder<String, Object> builder) {
builder.put("remarks",
ImmutableList.of(
ImmutableMap.of(
"description",
ImmutableList.of(
"This response conforms to the RDAP Operational Profile for gTLD Registries and"
+ " Registrars version 1.0"))));
}
static void addDomainBoilerplateRemarks(ImmutableMap.Builder<String, Object> builder) {
builder.put("remarks",
ImmutableList.of(
ImmutableMap.of(
"description",
ImmutableList.of(
"This response conforms to the RDAP Operational Profile for gTLD Registries and"
+ " Registrars version 1.0")),
ImmutableMap.of(
"title",
"EPP Status Codes",
"description",
ImmutableList.of(
"For more information on domain status codes, please visit"
+ " https://icann.org/epp"),
"links",
ImmutableList.of(
ImmutableMap.of(
"value", "https://icann.org/epp",
"rel", "alternate",
"href", "https://icann.org/epp",
"type", "text/html"))),
ImmutableMap.of(
"description",
ImmutableList.of(
"URL of the ICANN Whois Inaccuracy Complaint Form: https://www.icann.org/wicf"),
"links",
ImmutableList.of(
ImmutableMap.of(
"value", "https://www.icann.org/wicf",
"rel", "alternate",
"href", "https://www.icann.org/wicf",
"type", "text/html")))));
}
}

View file

@ -19,6 +19,40 @@
"href" : "https://www.registry.google/about/rdap/index.html" "href" : "https://www.registry.google/about/rdap/index.html"
} }
] ]
},
{
"title" : "RDAP Terms of Service",
"description" :
[
"By querying our Domain Database, you are agreeing to comply with these terms so please read them carefully.",
"Any information provided is 'as is' without any guarantee of accuracy.",
"Please do not misuse the Domain Database. It is intended solely for query-based access.",
"Don't use the Domain Database to allow, enable, or otherwise support the transmission of mass unsolicited, commercial advertising or solicitations.",
"Don't access our Domain Database through the use of high volume, automated electronic processes that send queries or data to the systems of Charleston Road Registry or any ICANN-accredited registrar.",
"You may only use the information contained in the Domain Database for lawful purposes.",
"Do not compile, repackage, disseminate, or otherwise use the information contained in the Domain Database in its entirety, or in any substantial portion, without our prior written permission.",
"We may retain certain details about queries to our Domain Database for the purposes of detecting and preventing misuse.",
"We reserve the right to restrict or deny your access to the database if we suspect that you have failed to comply with these terms.",
"We reserve the right to modify this agreement at any time."
],
"links" :
[
{
"value" : "https://example.tld/rdap/help/tos",
"rel" : "alternate",
"href" : "https://www.registry.google/about/rdap/tos.html",
"type" : "text/html"
}
]
}
],
"remarks" :
[
{
"description" :
[
"This response conforms to the RDAP Operational Profile for gTLD Registries and Registrars version 1.0"
]
} }
] ]
} }

View file

@ -0,0 +1,40 @@
{
"rdapConformance" : ["rdap_level_0"],
"notices" :
[
{
"title" : "RDAP Terms of Service",
"description" :
[
"By querying our Domain Database, you are agreeing to comply with these terms so please read them carefully.",
"Any information provided is 'as is' without any guarantee of accuracy.",
"Please do not misuse the Domain Database. It is intended solely for query-based access.",
"Don't use the Domain Database to allow, enable, or otherwise support the transmission of mass unsolicited, commercial advertising or solicitations.",
"Don't access our Domain Database through the use of high volume, automated electronic processes that send queries or data to the systems of Charleston Road Registry or any ICANN-accredited registrar.",
"You may only use the information contained in the Domain Database for lawful purposes.",
"Do not compile, repackage, disseminate, or otherwise use the information contained in the Domain Database in its entirety, or in any substantial portion, without our prior written permission.",
"We may retain certain details about queries to our Domain Database for the purposes of detecting and preventing misuse.",
"We reserve the right to restrict or deny your access to the database if we suspect that you have failed to comply with these terms.",
"We reserve the right to modify this agreement at any time."
],
"links" :
[
{
"value" : "https://example.tld/rdap/help/tos",
"rel" : "alternate",
"href" : "https://www.registry.google/about/rdap/tos.html",
"type" : "text/html"
}
]
}
],
"remarks" :
[
{
"description" :
[
"This response conforms to the RDAP Operational Profile for gTLD Registries and Registrars version 1.0"
]
}
]
}

View file

@ -120,5 +120,42 @@
"port43": "whois.example.tld" "port43": "whois.example.tld"
} }
], ],
"rdapConformance": [ "rdap_level_0" ] "rdapConformance": [ "rdap_level_0" ],
"notices" :
[
{
"title" : "RDAP Terms of Service",
"description" :
[
"By querying our Domain Database, you are agreeing to comply with these terms so please read them carefully.",
"Any information provided is 'as is' without any guarantee of accuracy.",
"Please do not misuse the Domain Database. It is intended solely for query-based access.",
"Don't use the Domain Database to allow, enable, or otherwise support the transmission of mass unsolicited, commercial advertising or solicitations.",
"Don't access our Domain Database through the use of high volume, automated electronic processes that send queries or data to the systems of Charleston Road Registry or any ICANN-accredited registrar.",
"You may only use the information contained in the Domain Database for lawful purposes.",
"Do not compile, repackage, disseminate, or otherwise use the information contained in the Domain Database in its entirety, or in any substantial portion, without our prior written permission.",
"We may retain certain details about queries to our Domain Database for the purposes of detecting and preventing misuse.",
"We reserve the right to restrict or deny your access to the database if we suspect that you have failed to comply with these terms.",
"We reserve the right to modify this agreement at any time."
],
"links" :
[
{
"value" : "https://example.com/rdap/help/tos",
"rel" : "alternate",
"href" : "https://www.registry.google/about/rdap/tos.html",
"type" : "text/html"
}
]
}
],
"remarks" :
[
{
"description" :
[
"This response conforms to the RDAP Operational Profile for gTLD Registries and Registrars version 1.0"
]
}
]
} }

View file

@ -621,5 +621,73 @@
], ],
"rdapConformance": [ "rdapConformance": [
"rdap_level_0" "rdap_level_0"
],
"notices" :
[
{
"title" : "RDAP Terms of Service",
"description" :
[
"By querying our Domain Database, you are agreeing to comply with these terms so please read them carefully.",
"Any information provided is 'as is' without any guarantee of accuracy.",
"Please do not misuse the Domain Database. It is intended solely for query-based access.",
"Don't use the Domain Database to allow, enable, or otherwise support the transmission of mass unsolicited, commercial advertising or solicitations.",
"Don't access our Domain Database through the use of high volume, automated electronic processes that send queries or data to the systems of Charleston Road Registry or any ICANN-accredited registrar.",
"You may only use the information contained in the Domain Database for lawful purposes.",
"Do not compile, repackage, disseminate, or otherwise use the information contained in the Domain Database in its entirety, or in any substantial portion, without our prior written permission.",
"We may retain certain details about queries to our Domain Database for the purposes of detecting and preventing misuse.",
"We reserve the right to restrict or deny your access to the database if we suspect that you have failed to comply with these terms.",
"We reserve the right to modify this agreement at any time."
],
"links" :
[
{
"value" : "https://example.com/rdap/help/tos",
"rel" : "alternate",
"href" : "https://www.registry.google/about/rdap/tos.html",
"type" : "text/html"
}
]
}
],
"remarks" :
[
{
"description" :
[
"This response conforms to the RDAP Operational Profile for gTLD Registries and Registrars version 1.0"
]
},
{
"title" : "EPP Status Codes",
"description" :
[
"For more information on domain status codes, please visit https://icann.org/epp"
],
"links" :
[
{
"value" : "https://icann.org/epp",
"rel" : "alternate",
"href" : "https://icann.org/epp",
"type" : "text/html"
}
]
},
{
"description" :
[
"URL of the ICANN Whois Inaccuracy Complaint Form: https://www.icann.org/wicf"
],
"links" :
[
{
"value" : "https://www.icann.org/wicf",
"rel" : "alternate",
"href" : "https://www.icann.org/wicf",
"type" : "text/html"
}
]
}
] ]
} }

View file

@ -43,5 +43,42 @@
"port43": "whois.example.tld" "port43": "whois.example.tld"
} }
], ],
"rdapConformance" : ["rdap_level_0"] "rdapConformance" : ["rdap_level_0"],
"notices" :
[
{
"title" : "RDAP Terms of Service",
"description" :
[
"By querying our Domain Database, you are agreeing to comply with these terms so please read them carefully.",
"Any information provided is 'as is' without any guarantee of accuracy.",
"Please do not misuse the Domain Database. It is intended solely for query-based access.",
"Don't use the Domain Database to allow, enable, or otherwise support the transmission of mass unsolicited, commercial advertising or solicitations.",
"Don't access our Domain Database through the use of high volume, automated electronic processes that send queries or data to the systems of Charleston Road Registry or any ICANN-accredited registrar.",
"You may only use the information contained in the Domain Database for lawful purposes.",
"Do not compile, repackage, disseminate, or otherwise use the information contained in the Domain Database in its entirety, or in any substantial portion, without our prior written permission.",
"We may retain certain details about queries to our Domain Database for the purposes of detecting and preventing misuse.",
"We reserve the right to restrict or deny your access to the database if we suspect that you have failed to comply with these terms.",
"We reserve the right to modify this agreement at any time."
],
"links" :
[
{
"value" : "https://example.tld/rdap/help/tos",
"rel" : "alternate",
"href" : "https://www.registry.google/about/rdap/tos.html",
"type" : "text/html"
}
]
}
],
"remarks" :
[
{
"description" :
[
"This response conforms to the RDAP Operational Profile for gTLD Registries and Registrars version 1.0"
]
}
]
} }

View file

@ -3,5 +3,42 @@
"rdapConformance" : "rdapConformance" :
[ [
"rdap_level_0" "rdap_level_0"
],
"notices" :
[
{
"title" : "RDAP Terms of Service",
"description" :
[
"By querying our Domain Database, you are agreeing to comply with these terms so please read them carefully.",
"Any information provided is 'as is' without any guarantee of accuracy.",
"Please do not misuse the Domain Database. It is intended solely for query-based access.",
"Don't use the Domain Database to allow, enable, or otherwise support the transmission of mass unsolicited, commercial advertising or solicitations.",
"Don't access our Domain Database through the use of high volume, automated electronic processes that send queries or data to the systems of Charleston Road Registry or any ICANN-accredited registrar.",
"You may only use the information contained in the Domain Database for lawful purposes.",
"Do not compile, repackage, disseminate, or otherwise use the information contained in the Domain Database in its entirety, or in any substantial portion, without our prior written permission.",
"We may retain certain details about queries to our Domain Database for the purposes of detecting and preventing misuse.",
"We reserve the right to restrict or deny your access to the database if we suspect that you have failed to comply with these terms.",
"We reserve the right to modify this agreement at any time."
],
"links" :
[
{
"value" : "http://myserver.google.com/help/tos",
"rel" : "alternate",
"href" : "https://www.registry.google/about/rdap/tos.html",
"type" : "text/html"
}
]
}
],
"remarks" :
[
{
"description" :
[
"This response conforms to the RDAP Operational Profile for gTLD Registries and Registrars version 1.0"
]
}
] ]
} }

View file

@ -0,0 +1,75 @@
{
"key" : "value",
"rdapConformance" :
[
"rdap_level_0"
],
"notices" :
[
{
"title" : "RDAP Terms of Service",
"description" :
[
"By querying our Domain Database, you are agreeing to comply with these terms so please read them carefully.",
"Any information provided is 'as is' without any guarantee of accuracy.",
"Please do not misuse the Domain Database. It is intended solely for query-based access.",
"Don't use the Domain Database to allow, enable, or otherwise support the transmission of mass unsolicited, commercial advertising or solicitations.",
"Don't access our Domain Database through the use of high volume, automated electronic processes that send queries or data to the systems of Charleston Road Registry or any ICANN-accredited registrar.",
"You may only use the information contained in the Domain Database for lawful purposes.",
"Do not compile, repackage, disseminate, or otherwise use the information contained in the Domain Database in its entirety, or in any substantial portion, without our prior written permission.",
"We may retain certain details about queries to our Domain Database for the purposes of detecting and preventing misuse.",
"We reserve the right to restrict or deny your access to the database if we suspect that you have failed to comply with these terms.",
"We reserve the right to modify this agreement at any time."
],
"links" :
[
{
"value" : "http://myserver.google.com/help/tos",
"rel" : "alternate",
"href" : "https://www.registry.google/about/rdap/tos.html",
"type" : "text/html"
}
]
}
],
"remarks" :
[
{
"description" :
[
"This response conforms to the RDAP Operational Profile for gTLD Registries and Registrars version 1.0"
]
},
{
"title" : "EPP Status Codes",
"description" :
[
"For more information on domain status codes, please visit https://icann.org/epp"
],
"links" :
[
{
"value" : "https://icann.org/epp",
"rel" : "alternate",
"href" : "https://icann.org/epp",
"type" : "text/html"
}
]
},
{
"description" :
[
"URL of the ICANN Whois Inaccuracy Complaint Form: https://www.icann.org/wicf"
],
"links" :
[
{
"value" : "https://www.icann.org/wicf",
"rel" : "alternate",
"href" : "https://www.icann.org/wicf",
"type" : "text/html"
}
]
}
]
}