mirror of
https://github.com/google/nomulus.git
synced 2025-05-13 16:07:15 +02:00
Save the RDAP request time globally instead of passing it around
Also removed the rdapWhoisServer value, as it's just null and will likely stay that way (it isn't mentioned in the RDAP response profile) If it'll ever become required, we can add it back. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=247643981
This commit is contained in:
parent
b10f880b7f
commit
a0040c5eda
15 changed files with 197 additions and 320 deletions
|
@ -969,20 +969,6 @@ public final class RegistryConfig {
|
|||
return 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* WHOIS server displayed in RDAP query responses. As per Gustavo Lozano of ICANN, this should
|
||||
* be omitted, but the ICANN operational profile doesn't actually say that, so it's good to have
|
||||
* the ability to reinstate this field if necessary.
|
||||
*
|
||||
* @see google.registry.rdap.RdapActionBase
|
||||
*/
|
||||
@Nullable
|
||||
@Provides
|
||||
@Config("rdapWhoisServer")
|
||||
public static String provideRdapWhoisServer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redaction text for email address in WHOIS
|
||||
*
|
||||
|
|
|
@ -49,13 +49,11 @@ import google.registry.request.Parameter;
|
|||
import google.registry.request.RequestMethod;
|
||||
import google.registry.request.RequestPath;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.util.Clock;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
|
@ -86,7 +84,6 @@ public abstract class RdapActionBase implements Runnable {
|
|||
}
|
||||
|
||||
@Inject Response response;
|
||||
@Inject Clock clock;
|
||||
@Inject @RequestMethod Action.Method requestMethod;
|
||||
@Inject @RequestPath String requestPath;
|
||||
@Inject RdapAuthorization rdapAuthorization;
|
||||
|
@ -94,7 +91,6 @@ public abstract class RdapActionBase implements Runnable {
|
|||
@Inject @Parameter("registrar") Optional<String> registrarParam;
|
||||
@Inject @Parameter("includeDeleted") Optional<Boolean> includeDeletedParam;
|
||||
@Inject @Parameter("formatOutput") Optional<Boolean> formatOutputParam;
|
||||
@Inject @Config("rdapWhoisServer") @Nullable String rdapWhoisServer;
|
||||
@Inject @Config("rdapResultSetMaxSize") int rdapResultSetMaxSize;
|
||||
@Inject RdapMetrics rdapMetrics;
|
||||
|
||||
|
@ -242,8 +238,8 @@ public abstract class RdapActionBase implements Runnable {
|
|||
* <p>This is true if the resource is not deleted, or the request wants to see deleted items, and
|
||||
* is authorized to do so.
|
||||
*/
|
||||
boolean isAuthorized(EppResource eppResource, DateTime now) {
|
||||
return now.isBefore(eppResource.getDeletionTime())
|
||||
boolean isAuthorized(EppResource eppResource) {
|
||||
return getRequestTime().isBefore(eppResource.getDeletionTime())
|
||||
|| (shouldIncludeDeleted()
|
||||
&& rdapAuthorization
|
||||
.isAuthorizedForClientId(eppResource.getPersistedCurrentSponsorClientId()));
|
||||
|
@ -257,8 +253,8 @@ public abstract class RdapActionBase implements Runnable {
|
|||
* do so, and:
|
||||
* 2. The request did not specify a registrar to filter on, or the registrar matches.
|
||||
*/
|
||||
boolean shouldBeVisible(EppResource eppResource, DateTime now) {
|
||||
return isAuthorized(eppResource, now)
|
||||
boolean shouldBeVisible(EppResource eppResource) {
|
||||
return isAuthorized(eppResource)
|
||||
&& (!registrarParam.isPresent()
|
||||
|| registrarParam.get().equals(eppResource.getPersistedCurrentSponsorClientId()));
|
||||
}
|
||||
|
@ -271,8 +267,8 @@ public abstract class RdapActionBase implements Runnable {
|
|||
* forward in time to empty),
|
||||
* 2. The request did not specify a registrar to filter on, or the registrar matches.
|
||||
*/
|
||||
boolean shouldBeVisible(Optional<? extends EppResource> eppResource, DateTime now) {
|
||||
return eppResource.isPresent() && shouldBeVisible(eppResource.get(), now);
|
||||
boolean shouldBeVisible(Optional<? extends EppResource> eppResource) {
|
||||
return eppResource.isPresent() && shouldBeVisible(eppResource.get());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -468,7 +464,6 @@ public abstract class RdapActionBase implements Runnable {
|
|||
*
|
||||
* @param query an already-defined query to be run; a filter on currentSponsorClientId will be
|
||||
* added if appropriate
|
||||
* @param now the time as of which to evaluate the query
|
||||
* @param checkForVisibility true if the results should be checked to make sure they are visible;
|
||||
* normally this should be equal to the shouldIncludeDeleted setting, but in cases where
|
||||
* the query could not check deletion status (due to Datastore limitations such as the
|
||||
|
@ -483,7 +478,7 @@ public abstract class RdapActionBase implements Runnable {
|
|||
* query is greater than or equal to the maximum number we might have expected
|
||||
*/
|
||||
<T extends EppResource> RdapResultSet<T> getMatchingResources(
|
||||
Query<T> query, boolean checkForVisibility, DateTime now, int querySizeLimit) {
|
||||
Query<T> query, boolean checkForVisibility, int querySizeLimit) {
|
||||
Optional<String> desiredRegistrar = getDesiredRegistrar();
|
||||
if (desiredRegistrar.isPresent()) {
|
||||
query = query.filter("currentSponsorClientId", desiredRegistrar.get());
|
||||
|
@ -496,7 +491,7 @@ public abstract class RdapActionBase implements Runnable {
|
|||
int numResourcesQueried = 0;
|
||||
boolean someExcluded = false;
|
||||
for (T resource : query) {
|
||||
if (shouldBeVisible(resource, now)) {
|
||||
if (shouldBeVisible(resource)) {
|
||||
resources.add(resource);
|
||||
} else {
|
||||
someExcluded = true;
|
||||
|
@ -542,4 +537,9 @@ public abstract class RdapActionBase implements Runnable {
|
|||
metricInformationBuilder.setPrefixLength(partialStringQuery.getInitialString().length());
|
||||
return partialStringQuery;
|
||||
}
|
||||
|
||||
/** Returns the DateTime this request took place. */
|
||||
DateTime getRequestTime() {
|
||||
return rdapJsonFormatter.getRequestTime();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ import google.registry.request.HttpException.NotFoundException;
|
|||
import google.registry.request.auth.Auth;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** RDAP (new WHOIS) action for domain requests. */
|
||||
@Action(
|
||||
|
@ -48,7 +47,6 @@ public class RdapDomainAction extends RdapActionBase {
|
|||
|
||||
@Override
|
||||
public RdapDomain getJsonObjectForResource(String pathSearchString, boolean isHeadRequest) {
|
||||
DateTime now = clock.nowUtc();
|
||||
pathSearchString = canonicalizeName(pathSearchString);
|
||||
try {
|
||||
validateDomainName(pathSearchString);
|
||||
|
@ -61,14 +59,14 @@ public class RdapDomainAction extends RdapActionBase {
|
|||
// The query string is not used; the RDAP syntax is /rdap/domain/mydomain.com.
|
||||
Optional<DomainBase> domainBase =
|
||||
loadByForeignKey(
|
||||
DomainBase.class, pathSearchString, shouldIncludeDeleted() ? START_OF_TIME : now);
|
||||
if (!shouldBeVisible(domainBase, now)) {
|
||||
DomainBase.class,
|
||||
pathSearchString,
|
||||
shouldIncludeDeleted() ? START_OF_TIME : rdapJsonFormatter.getRequestTime());
|
||||
if (!shouldBeVisible(domainBase)) {
|
||||
throw new NotFoundException(pathSearchString + " not found");
|
||||
}
|
||||
return rdapJsonFormatter.makeRdapJsonForDomain(
|
||||
domainBase.get(),
|
||||
rdapWhoisServer,
|
||||
now,
|
||||
OutputDataType.FULL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,6 @@ import java.util.List;
|
|||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* RDAP (new WHOIS) action for domain search requests.
|
||||
|
@ -93,7 +92,6 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
@Override
|
||||
public DomainSearchResponse getJsonObjectForResource(
|
||||
String pathSearchString, boolean isHeadRequest) {
|
||||
DateTime now = clock.nowUtc();
|
||||
// RDAP syntax example: /rdap/domains?name=exam*.com.
|
||||
// The pathSearchString is not used by search commands.
|
||||
if (pathSearchString.length() > 0) {
|
||||
|
@ -115,8 +113,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
} catch (Exception e) {
|
||||
throw new BadRequestException("Invalid value of nsLdhName parameter");
|
||||
}
|
||||
results = searchByDomainName(
|
||||
recordWildcardType(RdapSearchPattern.create(asciiName, true)), now);
|
||||
results = searchByDomainName(recordWildcardType(RdapSearchPattern.create(asciiName, true)));
|
||||
} else if (nsLdhNameParam.isPresent()) {
|
||||
metricInformationBuilder.setSearchType(SearchType.BY_NAMESERVER_NAME);
|
||||
// syntax: /rdap/domains?nsLdhName=ns1.exam*.com
|
||||
|
@ -126,7 +123,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
throw new BadRequestException("Invalid value of nsLdhName parameter");
|
||||
}
|
||||
results = searchByNameserverLdhName(
|
||||
recordWildcardType(RdapSearchPattern.create(nsLdhNameParam.get(), true)), now);
|
||||
recordWildcardType(RdapSearchPattern.create(nsLdhNameParam.get(), true)));
|
||||
} else {
|
||||
metricInformationBuilder.setSearchType(SearchType.BY_NAMESERVER_ADDRESS);
|
||||
metricInformationBuilder.setWildcardType(WildcardType.NO_WILDCARD);
|
||||
|
@ -138,7 +135,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
} catch (IllegalArgumentException e) {
|
||||
throw new BadRequestException("Invalid value of nsIp parameter");
|
||||
}
|
||||
results = searchByNameserverIp(inetAddress, now);
|
||||
results = searchByNameserverIp(inetAddress);
|
||||
}
|
||||
if (results.domainSearchResults().isEmpty()) {
|
||||
throw new NotFoundException("No domains found");
|
||||
|
@ -158,12 +155,11 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
* <p>Searches which include deleted entries are effectively treated as if they have a wildcard,
|
||||
* since the same name can return multiple results.
|
||||
*/
|
||||
private DomainSearchResponse searchByDomainName(
|
||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||
private DomainSearchResponse searchByDomainName(final RdapSearchPattern partialStringQuery) {
|
||||
// Handle queries without a wildcard -- just load by foreign key. We can't do this if deleted
|
||||
// entries are included, because there may be multiple nameservers with the same name.
|
||||
if (!partialStringQuery.getHasWildcard() && !shouldIncludeDeleted()) {
|
||||
return searchByDomainNameWithoutWildcard(partialStringQuery, now);
|
||||
return searchByDomainNameWithoutWildcard(partialStringQuery);
|
||||
}
|
||||
// Handle queries with a wildcard and initial search string. We require either a TLD or an
|
||||
// initial string at least MIN_INITIAL_STRING_LENGTH long.
|
||||
|
@ -177,32 +173,29 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
+ " without a TLD suffix",
|
||||
RdapSearchPattern.MIN_INITIAL_STRING_LENGTH));
|
||||
}
|
||||
return searchByDomainNameWithInitialString(partialStringQuery, now);
|
||||
return searchByDomainNameWithInitialString(partialStringQuery);
|
||||
}
|
||||
if (partialStringQuery.getSuffix() == null) {
|
||||
throw new UnprocessableEntityException(
|
||||
"Initial search string is required for wildcard domain searches without a TLD suffix");
|
||||
}
|
||||
return searchByDomainNameByTld(partialStringQuery.getSuffix(), now);
|
||||
return searchByDomainNameByTld(partialStringQuery.getSuffix());
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for domains by domain name without a wildcard or interest in deleted entries.
|
||||
*/
|
||||
private DomainSearchResponse searchByDomainNameWithoutWildcard(
|
||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||
final RdapSearchPattern partialStringQuery) {
|
||||
Optional<DomainBase> domainBase =
|
||||
loadByForeignKey(DomainBase.class, partialStringQuery.getInitialString(), now);
|
||||
loadByForeignKey(DomainBase.class, partialStringQuery.getInitialString(), getRequestTime());
|
||||
return makeSearchResults(
|
||||
shouldBeVisible(domainBase, now)
|
||||
? ImmutableList.of(domainBase.get())
|
||||
: ImmutableList.of(),
|
||||
now);
|
||||
shouldBeVisible(domainBase) ? ImmutableList.of(domainBase.get()) : ImmutableList.of());
|
||||
}
|
||||
|
||||
/** Searches for domains by domain name with an initial string, wildcard and possible suffix. */
|
||||
private DomainSearchResponse searchByDomainNameWithInitialString(
|
||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||
final RdapSearchPattern partialStringQuery) {
|
||||
// We can't query for undeleted domains as part of the query itself; that would require an
|
||||
// inequality query on deletion time, and we are already using inequality queries on
|
||||
// fullyQualifiedDomainName. So we instead pick an arbitrary limit of
|
||||
|
@ -227,11 +220,11 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
}
|
||||
query = query.limit(querySizeLimit);
|
||||
// Always check for visibility, because we couldn't look at the deletionTime in the query.
|
||||
return makeSearchResults(getMatchingResources(query, true, now, querySizeLimit), now);
|
||||
return makeSearchResults(getMatchingResources(query, true, querySizeLimit));
|
||||
}
|
||||
|
||||
/** Searches for domains by domain name with a TLD suffix. */
|
||||
private DomainSearchResponse searchByDomainNameByTld(String tld, DateTime now) {
|
||||
private DomainSearchResponse searchByDomainNameByTld(String tld) {
|
||||
// Even though we are not searching on fullyQualifiedDomainName, we want the results to come
|
||||
// back ordered by name, so we are still in the same boat as
|
||||
// searchByDomainNameWithInitialString, unable to perform an inequality query on deletion time.
|
||||
|
@ -246,7 +239,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
query = query.filter("fullyQualifiedDomainName >", cursorString.get());
|
||||
}
|
||||
query = query.order("fullyQualifiedDomainName").limit(querySizeLimit);
|
||||
return makeSearchResults(getMatchingResources(query, true, now, querySizeLimit), now);
|
||||
return makeSearchResults(getMatchingResources(query, true, querySizeLimit));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -259,13 +252,13 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
* domains which used to be connected to an undeleted nameserver.
|
||||
*/
|
||||
private DomainSearchResponse searchByNameserverLdhName(
|
||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||
Iterable<Key<HostResource>> hostKeys = getNameserverRefsByLdhName(partialStringQuery, now);
|
||||
final RdapSearchPattern partialStringQuery) {
|
||||
Iterable<Key<HostResource>> hostKeys = getNameserverRefsByLdhName(partialStringQuery);
|
||||
if (Iterables.isEmpty(hostKeys)) {
|
||||
metricInformationBuilder.setNumHostsRetrieved(0);
|
||||
throw new NotFoundException("No matching nameservers found");
|
||||
}
|
||||
return searchByNameserverRefs(hostKeys, now);
|
||||
return searchByNameserverRefs(hostKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -279,14 +272,14 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
* domain and just list all of its subordinate hosts.
|
||||
*/
|
||||
private Iterable<Key<HostResource>> getNameserverRefsByLdhName(
|
||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||
final RdapSearchPattern partialStringQuery) {
|
||||
// Handle queries without a wildcard.
|
||||
if (!partialStringQuery.getHasWildcard()) {
|
||||
return getNameserverRefsByLdhNameWithoutWildcard(partialStringQuery, now);
|
||||
return getNameserverRefsByLdhNameWithoutWildcard(partialStringQuery);
|
||||
}
|
||||
// Handle queries with a wildcard and suffix (specifying a suprerordinate domain).
|
||||
if (partialStringQuery.getSuffix() != null) {
|
||||
return getNameserverRefsByLdhNameWithSuffix(partialStringQuery, now);
|
||||
return getNameserverRefsByLdhNameWithSuffix(partialStringQuery);
|
||||
}
|
||||
// If there's no suffix, query the host resources. Query the resources themselves, rather than
|
||||
// the foreign key indexes, because then we have an index on fully qualified host name and
|
||||
|
@ -313,7 +306,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
|
||||
/** Assembles a list of {@link HostResource} keys by name when the pattern has no wildcard. */
|
||||
private Iterable<Key<HostResource>> getNameserverRefsByLdhNameWithoutWildcard(
|
||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||
final RdapSearchPattern partialStringQuery) {
|
||||
// If we need to check the sponsoring registrar, we need to load the resource rather than just
|
||||
// the key.
|
||||
Optional<String> desiredRegistrar = getDesiredRegistrar();
|
||||
|
@ -322,7 +315,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
loadByForeignKey(
|
||||
HostResource.class,
|
||||
partialStringQuery.getInitialString(),
|
||||
shouldIncludeDeleted() ? START_OF_TIME : now);
|
||||
shouldIncludeDeleted() ? START_OF_TIME : getRequestTime());
|
||||
return (!host.isPresent()
|
||||
|| !desiredRegistrar.get().equals(host.get().getPersistedCurrentSponsorClientId()))
|
||||
? ImmutableList.of()
|
||||
|
@ -332,14 +325,14 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
loadAndGetKey(
|
||||
HostResource.class,
|
||||
partialStringQuery.getInitialString(),
|
||||
shouldIncludeDeleted() ? START_OF_TIME : now);
|
||||
shouldIncludeDeleted() ? START_OF_TIME : getRequestTime());
|
||||
return (hostKey == null) ? ImmutableList.of() : ImmutableList.of(hostKey);
|
||||
}
|
||||
}
|
||||
|
||||
/** Assembles a list of {@link HostResource} keys by name using a superordinate domain suffix. */
|
||||
private Iterable<Key<HostResource>> getNameserverRefsByLdhNameWithSuffix(
|
||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||
final RdapSearchPattern partialStringQuery) {
|
||||
// The suffix must be a domain that we manage. That way, we can look up the domain and search
|
||||
// through the subordinate hosts. This is more efficient, and lets us permit wildcard searches
|
||||
// with no initial string.
|
||||
|
@ -347,7 +340,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
loadByForeignKey(
|
||||
DomainBase.class,
|
||||
partialStringQuery.getSuffix(),
|
||||
shouldIncludeDeleted() ? START_OF_TIME : now)
|
||||
shouldIncludeDeleted() ? START_OF_TIME : getRequestTime())
|
||||
.orElseThrow(
|
||||
() ->
|
||||
new UnprocessableEntityException(
|
||||
|
@ -362,14 +355,19 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
if (desiredRegistrar.isPresent()) {
|
||||
Optional<HostResource> host =
|
||||
loadByForeignKey(
|
||||
HostResource.class, fqhn, shouldIncludeDeleted() ? START_OF_TIME : now);
|
||||
HostResource.class,
|
||||
fqhn,
|
||||
shouldIncludeDeleted() ? START_OF_TIME : getRequestTime());
|
||||
if (host.isPresent()
|
||||
&& desiredRegistrar.get().equals(host.get().getPersistedCurrentSponsorClientId())) {
|
||||
builder.add(Key.create(host.get()));
|
||||
}
|
||||
} else {
|
||||
Key<HostResource> hostKey =
|
||||
loadAndGetKey(HostResource.class, fqhn, shouldIncludeDeleted() ? START_OF_TIME : now);
|
||||
loadAndGetKey(
|
||||
HostResource.class,
|
||||
fqhn,
|
||||
shouldIncludeDeleted() ? START_OF_TIME : getRequestTime());
|
||||
if (hostKey != null) {
|
||||
builder.add(hostKey);
|
||||
} else {
|
||||
|
@ -398,7 +396,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
* domains which used to be connected to an undeleted nameserver.
|
||||
*/
|
||||
private DomainSearchResponse searchByNameserverIp(
|
||||
final InetAddress inetAddress, final DateTime now) {
|
||||
final InetAddress inetAddress) {
|
||||
Query<HostResource> query =
|
||||
queryItems(
|
||||
HostResource.class,
|
||||
|
@ -412,7 +410,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
if (desiredRegistrar.isPresent()) {
|
||||
query = query.filter("currentSponsorClientId", desiredRegistrar.get());
|
||||
}
|
||||
return searchByNameserverRefs(query.keys(), now);
|
||||
return searchByNameserverRefs(query.keys());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -422,7 +420,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
* #searchByNameserverIp} after they assemble the relevant host keys.
|
||||
*/
|
||||
private DomainSearchResponse searchByNameserverRefs(
|
||||
final Iterable<Key<HostResource>> hostKeys, final DateTime now) {
|
||||
final Iterable<Key<HostResource>> hostKeys) {
|
||||
// We must break the query up into chunks, because the in operator is limited to 30 subqueries.
|
||||
// Since it is possible for the same domain to show up more than once in our result list (if
|
||||
// we do a wildcard nameserver search that returns multiple nameservers used by the same
|
||||
|
@ -439,14 +437,13 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
.type(DomainBase.class)
|
||||
.filter("nsHosts in", chunk);
|
||||
if (!shouldIncludeDeleted()) {
|
||||
query = query.filter("deletionTime >", now);
|
||||
query = query.filter("deletionTime >", getRequestTime());
|
||||
// If we are not performing an inequality query, we can filter on the cursor in the query.
|
||||
// Otherwise, we will need to filter the results afterward.
|
||||
} else if (cursorString.isPresent()) {
|
||||
query = query.filter("fullyQualifiedDomainName >", cursorString.get());
|
||||
}
|
||||
Stream<DomainBase> stream =
|
||||
Streams.stream(query).filter(domain -> isAuthorized(domain, now));
|
||||
Stream<DomainBase> stream = Streams.stream(query).filter(domain -> isAuthorized(domain));
|
||||
if (cursorString.isPresent()) {
|
||||
stream =
|
||||
stream.filter(
|
||||
|
@ -464,24 +461,22 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
(numHostKeysSearched >= maxNameserversInFirstStage)
|
||||
? IncompletenessWarningType.MIGHT_BE_INCOMPLETE
|
||||
: IncompletenessWarningType.COMPLETE,
|
||||
(numHostKeysSearched > 0) ? Optional.of((long) domains.size()) : Optional.empty(),
|
||||
now);
|
||||
(numHostKeysSearched > 0) ? Optional.of((long) domains.size()) : Optional.empty());
|
||||
}
|
||||
|
||||
/** Output JSON for a list of domains, with no incompleteness warnings. */
|
||||
private DomainSearchResponse makeSearchResults(List<DomainBase> domains, DateTime now) {
|
||||
private DomainSearchResponse makeSearchResults(List<DomainBase> domains) {
|
||||
return makeSearchResults(
|
||||
domains, IncompletenessWarningType.COMPLETE, Optional.of((long) domains.size()), now);
|
||||
domains, IncompletenessWarningType.COMPLETE, Optional.of((long) domains.size()));
|
||||
}
|
||||
|
||||
/** Output JSON from data in an {@link RdapResultSet} object. */
|
||||
private DomainSearchResponse makeSearchResults(
|
||||
RdapResultSet<DomainBase> resultSet, DateTime now) {
|
||||
RdapResultSet<DomainBase> resultSet) {
|
||||
return makeSearchResults(
|
||||
resultSet.resources(),
|
||||
resultSet.incompletenessWarningType(),
|
||||
Optional.of((long) resultSet.numResourcesRetrieved()),
|
||||
now);
|
||||
Optional.of((long) resultSet.numResourcesRetrieved()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -494,8 +489,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
private DomainSearchResponse makeSearchResults(
|
||||
List<DomainBase> domains,
|
||||
IncompletenessWarningType incompletenessWarningType,
|
||||
Optional<Long> numDomainsRetrieved,
|
||||
DateTime now) {
|
||||
Optional<Long> numDomainsRetrieved) {
|
||||
numDomainsRetrieved.ifPresent(metricInformationBuilder::setNumDomainsRetrieved);
|
||||
OutputDataType outputDataType =
|
||||
(domains.size() > 1) ? OutputDataType.SUMMARY : OutputDataType.FULL;
|
||||
|
@ -505,8 +499,9 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
Optional<String> newCursor = Optional.empty();
|
||||
for (DomainBase domain : Iterables.limit(domains, rdapResultSetMaxSize)) {
|
||||
newCursor = Optional.of(domain.getFullyQualifiedDomainName());
|
||||
builder.domainSearchResultsBuilder().add(
|
||||
rdapJsonFormatter.makeRdapJsonForDomain(domain, rdapWhoisServer, now, outputDataType));
|
||||
builder
|
||||
.domainSearchResultsBuilder()
|
||||
.add(rdapJsonFormatter.makeRdapJsonForDomain(domain, outputDataType));
|
||||
}
|
||||
if (rdapResultSetMaxSize < domains.size()) {
|
||||
builder.setNextPageUri(createNavigationUri(newCursor.get()));
|
||||
|
|
|
@ -33,7 +33,6 @@ import google.registry.request.HttpException.NotFoundException;
|
|||
import google.registry.request.auth.Auth;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* RDAP (new WHOIS) action for entity (contact and registrar) requests. the ICANN operational
|
||||
|
@ -62,7 +61,6 @@ public class RdapEntityAction extends RdapActionBase {
|
|||
@Override
|
||||
public RdapEntity getJsonObjectForResource(
|
||||
String pathSearchString, boolean isHeadRequest) {
|
||||
DateTime now = clock.nowUtc();
|
||||
// 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
|
||||
// includes both contacts and registrars, search for one first, then the other.
|
||||
|
@ -73,12 +71,10 @@ public class RdapEntityAction extends RdapActionBase {
|
|||
ContactResource contactResource = ofy().load().key(contactKey).now();
|
||||
// As per Andy Newton on the regext mailing list, contacts by themselves have no role, since
|
||||
// they are global, and might have different roles for different domains.
|
||||
if ((contactResource != null) && shouldBeVisible(contactResource, now)) {
|
||||
if ((contactResource != null) && shouldBeVisible(contactResource)) {
|
||||
return rdapJsonFormatter.makeRdapJsonForContact(
|
||||
contactResource,
|
||||
Optional.empty(),
|
||||
rdapWhoisServer,
|
||||
now,
|
||||
OutputDataType.FULL);
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +84,7 @@ public class RdapEntityAction extends RdapActionBase {
|
|||
Optional<Registrar> registrar = getRegistrarByIanaIdentifier(ianaIdentifier);
|
||||
if (registrar.isPresent() && shouldBeVisible(registrar.get())) {
|
||||
return rdapJsonFormatter.makeRdapJsonForRegistrar(
|
||||
registrar.get(), rdapWhoisServer, now, OutputDataType.FULL);
|
||||
registrar.get(), OutputDataType.FULL);
|
||||
}
|
||||
}
|
||||
// At this point, we have failed to find either a contact or a registrar.
|
||||
|
|
|
@ -43,7 +43,6 @@ import java.util.Comparator;
|
|||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* RDAP (new WHOIS) action for entity (contact and registrar) search requests.
|
||||
|
@ -111,7 +110,6 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
@Override
|
||||
public EntitySearchResponse getJsonObjectForResource(
|
||||
String pathSearchString, boolean isHeadRequest) {
|
||||
DateTime now = clock.nowUtc();
|
||||
|
||||
// RDAP syntax example: /rdap/entities?fn=Bobby%20Joe*.
|
||||
// The pathSearchString is not used by search commands.
|
||||
|
@ -166,8 +164,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
recordWildcardType(RdapSearchPattern.create(fnParam.get(), false)),
|
||||
cursorType,
|
||||
cursorQueryString,
|
||||
subtype,
|
||||
now);
|
||||
subtype);
|
||||
|
||||
// Search by handle.
|
||||
} else {
|
||||
|
@ -179,8 +176,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
recordWildcardType(RdapSearchPattern.create(handleParam.get(), false)),
|
||||
cursorType,
|
||||
cursorQueryString,
|
||||
subtype,
|
||||
now);
|
||||
subtype);
|
||||
}
|
||||
|
||||
// Build the result object and return it.
|
||||
|
@ -218,8 +214,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
final RdapSearchPattern partialStringQuery,
|
||||
CursorType cursorType,
|
||||
Optional<String> cursorQueryString,
|
||||
Subtype subtype,
|
||||
DateTime now) {
|
||||
Subtype subtype) {
|
||||
// Don't allow wildcard suffixes when searching for entities.
|
||||
if (partialStringQuery.getHasWildcard() && (partialStringQuery.getSuffix() != null)) {
|
||||
throw new UnprocessableEntityException(
|
||||
|
@ -282,10 +277,10 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
if (rdapAuthorization.role() != RdapAuthorization.Role.ADMINISTRATOR) {
|
||||
query = query.filter("currentSponsorClientId in", rdapAuthorization.clientIds());
|
||||
}
|
||||
resultSet = getMatchingResources(query, false, now, rdapResultSetMaxSize + 1);
|
||||
resultSet = getMatchingResources(query, false, rdapResultSetMaxSize + 1);
|
||||
}
|
||||
}
|
||||
return makeSearchResults(resultSet, registrars, QueryType.FULL_NAME, now);
|
||||
return makeSearchResults(resultSet, registrars, QueryType.FULL_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -302,8 +297,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
final RdapSearchPattern partialStringQuery,
|
||||
CursorType cursorType,
|
||||
Optional<String> cursorQueryString,
|
||||
Subtype subtype,
|
||||
DateTime now) {
|
||||
Subtype subtype) {
|
||||
if (partialStringQuery.getSuffix() != null) {
|
||||
throw new UnprocessableEntityException("Suffixes not allowed in entity handle searches");
|
||||
}
|
||||
|
@ -320,7 +314,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
.id(partialStringQuery.getInitialString())
|
||||
.now();
|
||||
contactResourceList =
|
||||
((contactResource != null) && shouldBeVisible(contactResource, now))
|
||||
((contactResource != null) && shouldBeVisible(contactResource))
|
||||
? ImmutableList.of(contactResource)
|
||||
: ImmutableList.of();
|
||||
}
|
||||
|
@ -335,8 +329,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
IncompletenessWarningType.COMPLETE,
|
||||
contactResourceList.size(),
|
||||
registrarList,
|
||||
QueryType.HANDLE,
|
||||
now);
|
||||
QueryType.HANDLE);
|
||||
// Handle queries with a wildcard (or including deleted), but no suffix. Because the handle
|
||||
// for registrars is the IANA identifier number, don't allow wildcard searches for registrars,
|
||||
// by simply not searching for registrars if a wildcard is present (unless the request is for
|
||||
|
@ -385,14 +378,12 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
getDeletedItemHandling(),
|
||||
querySizeLimit),
|
||||
shouldIncludeDeleted(),
|
||||
now,
|
||||
querySizeLimit);
|
||||
}
|
||||
return makeSearchResults(
|
||||
contactResultSet,
|
||||
registrars,
|
||||
QueryType.HANDLE,
|
||||
now);
|
||||
QueryType.HANDLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -417,15 +408,13 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
private EntitySearchResponse makeSearchResults(
|
||||
RdapResultSet<ContactResource> resultSet,
|
||||
List<Registrar> registrars,
|
||||
QueryType queryType,
|
||||
DateTime now) {
|
||||
QueryType queryType) {
|
||||
return makeSearchResults(
|
||||
resultSet.resources(),
|
||||
resultSet.incompletenessWarningType(),
|
||||
resultSet.numResourcesRetrieved(),
|
||||
registrars,
|
||||
queryType,
|
||||
now);
|
||||
queryType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -441,7 +430,6 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
* results
|
||||
* @param registrars the list of registrars which can be returned
|
||||
* @param queryType whether the query was by full name or by handle
|
||||
* @param now the current date and time
|
||||
* @return an {@link RdapSearchResults} object
|
||||
*/
|
||||
private EntitySearchResponse makeSearchResults(
|
||||
|
@ -449,8 +437,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
IncompletenessWarningType incompletenessWarningType,
|
||||
int numContactsRetrieved,
|
||||
List<Registrar> registrars,
|
||||
QueryType queryType,
|
||||
DateTime now) {
|
||||
QueryType queryType) {
|
||||
|
||||
metricInformationBuilder.setNumContactsRetrieved(numContactsRetrieved);
|
||||
|
||||
|
@ -476,8 +463,6 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
builder.entitySearchResultsBuilder().add(rdapJsonFormatter.makeRdapJsonForContact(
|
||||
contact,
|
||||
Optional.empty(),
|
||||
rdapWhoisServer,
|
||||
now,
|
||||
outputDataType));
|
||||
newCursor =
|
||||
Optional.of(
|
||||
|
@ -493,7 +478,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
.entitySearchResultsBuilder()
|
||||
.add(
|
||||
rdapJsonFormatter.makeRdapJsonForRegistrar(
|
||||
registrar, rdapWhoisServer, now, outputDataType));
|
||||
registrar, outputDataType));
|
||||
newCursor = Optional.of(REGISTRAR_CURSOR_PREFIX + registrar.getRegistrarName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,6 @@ import google.registry.rdap.RdapDataStructures.Event;
|
|||
import google.registry.rdap.RdapDataStructures.EventAction;
|
||||
import google.registry.rdap.RdapDataStructures.Link;
|
||||
import google.registry.rdap.RdapDataStructures.Notice;
|
||||
import google.registry.rdap.RdapDataStructures.Port43WhoisServer;
|
||||
import google.registry.rdap.RdapDataStructures.PublicId;
|
||||
import google.registry.rdap.RdapDataStructures.RdapStatus;
|
||||
import google.registry.rdap.RdapObjectClasses.RdapDomain;
|
||||
|
@ -59,6 +58,7 @@ import google.registry.rdap.RdapObjectClasses.Vcard;
|
|||
import google.registry.rdap.RdapObjectClasses.VcardArray;
|
||||
import google.registry.request.FullServletPath;
|
||||
import google.registry.request.HttpException.InternalServerErrorException;
|
||||
import google.registry.util.Clock;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
|
@ -87,11 +87,13 @@ import org.joda.time.DateTimeComparator;
|
|||
*/
|
||||
public class RdapJsonFormatter {
|
||||
|
||||
private DateTime requestTime = null;
|
||||
|
||||
@Inject @Config("rdapTos") ImmutableList<String> rdapTos;
|
||||
@Inject @Config("rdapTosStaticUrl") @Nullable String rdapTosStaticUrl;
|
||||
@Inject @FullServletPath String fullServletPath;
|
||||
@Inject RdapAuthorization rdapAuthorization;
|
||||
@Inject Clock clock;
|
||||
@Inject RdapJsonFormatter() {}
|
||||
|
||||
/**
|
||||
|
@ -213,15 +215,10 @@ public class RdapJsonFormatter {
|
|||
* Creates a JSON object for a {@link DomainBase}.
|
||||
*
|
||||
* @param domainBase the domain resource object from which the JSON object should be created
|
||||
* @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
|
||||
* @param now the as-date
|
||||
* @param outputDataType whether to generate full or summary data
|
||||
*/
|
||||
RdapDomain makeRdapJsonForDomain(
|
||||
DomainBase domainBase,
|
||||
@Nullable String whoisServer,
|
||||
DateTime now,
|
||||
OutputDataType outputDataType) {
|
||||
RdapDomain.Builder builder = RdapDomain.builder();
|
||||
// RDAP Response Profile 15feb19 section 2.2:
|
||||
|
@ -232,7 +229,7 @@ public class RdapJsonFormatter {
|
|||
makeStatusValueList(
|
||||
domainBase.getStatusValues(),
|
||||
false, // isRedacted
|
||||
domainBase.getDeletionTime().isBefore(now)));
|
||||
domainBase.getDeletionTime().isBefore(getRequestTime())));
|
||||
builder.linksBuilder().add(
|
||||
makeSelfLink("domain", domainBase.getFullyQualifiedDomainName()));
|
||||
boolean displayContacts =
|
||||
|
@ -243,7 +240,7 @@ public class RdapJsonFormatter {
|
|||
if (outputDataType == OutputDataType.SUMMARY) {
|
||||
builder.remarksBuilder().add(RdapIcannStandardInformation.SUMMARY_DATA_REMARK);
|
||||
} else {
|
||||
ImmutableList<Event> events = makeEvents(domainBase, now);
|
||||
ImmutableList<Event> events = makeEvents(domainBase);
|
||||
builder.eventsBuilder().addAll(events);
|
||||
// Kick off the database loads of the nameservers that we will need, so it can load
|
||||
// asynchronously while we load and process the contacts.
|
||||
|
@ -267,26 +264,18 @@ public class RdapJsonFormatter {
|
|||
makeRdapJsonForContact(
|
||||
loadedContacts.get(designatedContact.getContactKey()),
|
||||
Optional.of(designatedContact.getType()),
|
||||
null,
|
||||
now,
|
||||
outputDataType))
|
||||
.forEach(builder.entitiesBuilder()::add);
|
||||
}
|
||||
builder
|
||||
.entitiesBuilder()
|
||||
.add(
|
||||
createInternalRegistrarEntity(
|
||||
domainBase.getCurrentSponsorClientId(), whoisServer, now));
|
||||
.add(createInternalRegistrarEntity(domainBase.getCurrentSponsorClientId()));
|
||||
// Add the nameservers to the data; the load was kicked off above for efficiency.
|
||||
for (HostResource hostResource
|
||||
: HOST_RESOURCE_ORDERING.immutableSortedCopy(loadedHosts.values())) {
|
||||
builder.nameserversBuilder().add(makeRdapJsonForHost(
|
||||
hostResource, null, now, outputDataType));
|
||||
builder.nameserversBuilder().add(makeRdapJsonForHost(hostResource, outputDataType));
|
||||
}
|
||||
}
|
||||
if (whoisServer != null) {
|
||||
builder.setPort43(Port43WhoisServer.create(whoisServer));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
@ -294,14 +283,8 @@ public class RdapJsonFormatter {
|
|||
* Creates a JSON object for the desired registrar to an existing list of JSON objects.
|
||||
*
|
||||
* @param clientId the registrar client ID
|
||||
* @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
|
||||
* @param now the as-date
|
||||
*/
|
||||
RdapEntity createInternalRegistrarEntity(
|
||||
String clientId,
|
||||
@Nullable String whoisServer,
|
||||
DateTime now) {
|
||||
RdapEntity createInternalRegistrarEntity(String clientId) {
|
||||
Optional<Registrar> registrar = Registrar.loadByClientIdCached(clientId);
|
||||
if (!registrar.isPresent()) {
|
||||
throw new InternalServerErrorException(
|
||||
|
@ -309,26 +292,17 @@ public class RdapJsonFormatter {
|
|||
}
|
||||
// TODO(b/130150723): we need to display the ABUSE contact for registrar object inside of Domain
|
||||
// responses. Currently, we use summary for any "internal" registrar.
|
||||
return makeRdapJsonForRegistrar(
|
||||
registrar.get(),
|
||||
whoisServer,
|
||||
now,
|
||||
OutputDataType.SUMMARY);
|
||||
return makeRdapJsonForRegistrar(registrar.get(), OutputDataType.SUMMARY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JSON object for a {@link HostResource}.
|
||||
*
|
||||
* @param hostResource the host resource object from which the JSON object should be created
|
||||
* @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
|
||||
* @param now the as-date
|
||||
* @param outputDataType whether to generate full or summary data
|
||||
*/
|
||||
RdapNameserver makeRdapJsonForHost(
|
||||
HostResource hostResource,
|
||||
@Nullable String whoisServer,
|
||||
DateTime now,
|
||||
OutputDataType outputDataType) {
|
||||
RdapNameserver.Builder builder = RdapNameserver.builder()
|
||||
.setHandle(hostResource.getRepoId())
|
||||
|
@ -336,11 +310,15 @@ public class RdapJsonFormatter {
|
|||
|
||||
ImmutableSet.Builder<StatusValue> statuses = new ImmutableSet.Builder<>();
|
||||
statuses.addAll(hostResource.getStatusValues());
|
||||
if (isLinked(Key.create(hostResource), now)) {
|
||||
if (isLinked(Key.create(hostResource), getRequestTime())) {
|
||||
statuses.add(StatusValue.LINKED);
|
||||
}
|
||||
if (hostResource.isSubordinate()
|
||||
&& ofy().load().key(hostResource.getSuperordinateDomain()).now().cloneProjectedAtTime(now)
|
||||
&& ofy()
|
||||
.load()
|
||||
.key(hostResource.getSuperordinateDomain())
|
||||
.now()
|
||||
.cloneProjectedAtTime(getRequestTime())
|
||||
.getStatusValues()
|
||||
.contains(StatusValue.PENDING_TRANSFER)) {
|
||||
statuses.add(StatusValue.PENDING_TRANSFER);
|
||||
|
@ -351,7 +329,7 @@ public class RdapJsonFormatter {
|
|||
makeStatusValueList(
|
||||
statuses.build(),
|
||||
false, // isRedacted
|
||||
hostResource.getDeletionTime().isBefore(now)));
|
||||
hostResource.getDeletionTime().isBefore(getRequestTime())));
|
||||
builder
|
||||
.linksBuilder()
|
||||
.add(makeSelfLink("nameserver", hostResource.getFullyQualifiedHostName()));
|
||||
|
@ -361,7 +339,7 @@ public class RdapJsonFormatter {
|
|||
if (outputDataType == OutputDataType.SUMMARY) {
|
||||
builder.remarksBuilder().add(RdapIcannStandardInformation.SUMMARY_DATA_REMARK);
|
||||
} else {
|
||||
builder.eventsBuilder().addAll(makeEvents(hostResource, now));
|
||||
builder.eventsBuilder().addAll(makeEvents(hostResource));
|
||||
}
|
||||
|
||||
// We MUST have the ip addresses: RDAP Response Profile 4.2.
|
||||
|
@ -372,13 +350,9 @@ public class RdapJsonFormatter {
|
|||
builder.ipv6Builder().add(InetAddresses.toAddrString(inetAddress));
|
||||
}
|
||||
}
|
||||
builder.entitiesBuilder().add(createInternalRegistrarEntity(
|
||||
hostResource.getPersistedCurrentSponsorClientId(),
|
||||
whoisServer,
|
||||
now));
|
||||
if (whoisServer != null) {
|
||||
builder.setPort43(Port43WhoisServer.create(whoisServer));
|
||||
}
|
||||
builder
|
||||
.entitiesBuilder()
|
||||
.add(createInternalRegistrarEntity(hostResource.getPersistedCurrentSponsorClientId()));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
@ -387,16 +361,11 @@ public class RdapJsonFormatter {
|
|||
*
|
||||
* @param contactResource the contact resource object from which the JSON object should be created
|
||||
* @param contactType the contact type to map to an RDAP role; if absent, no role is listed
|
||||
* @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
|
||||
* @param now the as-date
|
||||
* @param outputDataType whether to generate full or summary data
|
||||
*/
|
||||
RdapEntity makeRdapJsonForContact(
|
||||
ContactResource contactResource,
|
||||
Optional<DesignatedContact.Type> contactType,
|
||||
@Nullable String whoisServer,
|
||||
DateTime now,
|
||||
OutputDataType outputDataType) {
|
||||
boolean isAuthorized =
|
||||
rdapAuthorization.isAuthorizedForClientId(contactResource.getCurrentSponsorClientId());
|
||||
|
@ -408,11 +377,11 @@ public class RdapJsonFormatter {
|
|||
.statusBuilder()
|
||||
.addAll(
|
||||
makeStatusValueList(
|
||||
isLinked(Key.create(contactResource), now)
|
||||
isLinked(Key.create(contactResource), getRequestTime())
|
||||
? union(contactResource.getStatusValues(), StatusValue.LINKED)
|
||||
: contactResource.getStatusValues(),
|
||||
!isAuthorized,
|
||||
contactResource.getDeletionTime().isBefore(now)));
|
||||
contactResource.getDeletionTime().isBefore(getRequestTime())));
|
||||
|
||||
contactType.ifPresent(
|
||||
type -> entityBuilder.rolesBuilder().add(convertContactTypeToRdapRole(type)));
|
||||
|
@ -456,10 +425,7 @@ public class RdapJsonFormatter {
|
|||
if (outputDataType == OutputDataType.SUMMARY) {
|
||||
entityBuilder.remarksBuilder().add(RdapIcannStandardInformation.SUMMARY_DATA_REMARK);
|
||||
} else {
|
||||
entityBuilder.eventsBuilder().addAll(makeEvents(contactResource, now));
|
||||
}
|
||||
if (whoisServer != null) {
|
||||
entityBuilder.setPort43(Port43WhoisServer.create(whoisServer));
|
||||
entityBuilder.eventsBuilder().addAll(makeEvents(contactResource));
|
||||
}
|
||||
return entityBuilder.build();
|
||||
}
|
||||
|
@ -468,15 +434,10 @@ public class RdapJsonFormatter {
|
|||
* Creates a JSON object for a {@link Registrar}.
|
||||
*
|
||||
* @param registrar the registrar object from which the JSON object should be created
|
||||
* @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
|
||||
* @param now the as-date
|
||||
* @param outputDataType whether to generate full or summary data
|
||||
*/
|
||||
RdapEntity makeRdapJsonForRegistrar(
|
||||
Registrar registrar,
|
||||
@Nullable String whoisServer,
|
||||
DateTime now,
|
||||
OutputDataType outputDataType) {
|
||||
RdapEntity.Builder builder = RdapEntity.builder();
|
||||
Long ianaIdentifier = registrar.getIanaIdentifier();
|
||||
|
@ -521,11 +482,11 @@ public class RdapJsonFormatter {
|
|||
if (outputDataType == OutputDataType.SUMMARY) {
|
||||
builder.remarksBuilder().add(RdapIcannStandardInformation.SUMMARY_DATA_REMARK);
|
||||
} else {
|
||||
builder.eventsBuilder().addAll(makeEvents(registrar, now));
|
||||
builder.eventsBuilder().addAll(makeEvents(registrar));
|
||||
// include the registrar contacts as subentities
|
||||
ImmutableList<RdapEntity> registrarContacts =
|
||||
registrar.getContacts().stream()
|
||||
.map(registrarContact -> makeRdapJsonForRegistrarContact(registrarContact, null))
|
||||
.map(registrarContact -> makeRdapJsonForRegistrarContact(registrarContact))
|
||||
.filter(optional -> optional.isPresent())
|
||||
.map(optional -> optional.get())
|
||||
.collect(toImmutableList());
|
||||
|
@ -533,9 +494,6 @@ public class RdapJsonFormatter {
|
|||
// one is required by the RDAP response profile
|
||||
builder.entitiesBuilder().addAll(registrarContacts);
|
||||
}
|
||||
if (whoisServer != null) {
|
||||
builder.setPort43(Port43WhoisServer.create(whoisServer));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
@ -545,11 +503,9 @@ public class RdapJsonFormatter {
|
|||
* <p>Returns empty if this contact shouldn't be visible (doesn't have a role).
|
||||
*
|
||||
* @param registrarContact the registrar contact for which the JSON object should be created
|
||||
* @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
|
||||
*/
|
||||
static Optional<RdapEntity> makeRdapJsonForRegistrarContact(
|
||||
RegistrarContact registrarContact, @Nullable String whoisServer) {
|
||||
RegistrarContact registrarContact) {
|
||||
ImmutableList<RdapEntity.Role> roles = makeRdapRoleList(registrarContact);
|
||||
if (roles.isEmpty()) {
|
||||
return Optional.empty();
|
||||
|
@ -576,9 +532,6 @@ public class RdapJsonFormatter {
|
|||
vcardBuilder.add(Vcard.create("email", "text", emailAddress));
|
||||
}
|
||||
builder.setVcardArray(vcardBuilder.build());
|
||||
if (whoisServer != null) {
|
||||
builder.setPort43(Port43WhoisServer.create(whoisServer));
|
||||
}
|
||||
return Optional.of(builder.build());
|
||||
}
|
||||
|
||||
|
@ -627,7 +580,7 @@ public class RdapJsonFormatter {
|
|||
/**
|
||||
* Creates an event list for a domain, host or contact resource.
|
||||
*/
|
||||
private static ImmutableList<Event> makeEvents(EppResource resource, DateTime now) {
|
||||
private ImmutableList<Event> makeEvents(EppResource resource) {
|
||||
HashMap<EventAction, HistoryEntry> lastEntryOfType = Maps.newHashMap();
|
||||
// Events (such as transfer, but also create) can appear multiple times. We only want the last
|
||||
// time they appeared.
|
||||
|
@ -707,13 +660,13 @@ public class RdapJsonFormatter {
|
|||
// any EPP update (for example, by the passage of time).
|
||||
DateTime lastChangeTime =
|
||||
changeTimesBuilder.build().stream()
|
||||
.filter(changeTime -> changeTime.isBefore(now))
|
||||
.filter(changeTime -> changeTime.isBefore(getRequestTime()))
|
||||
.max(DateTimeComparator.getInstance())
|
||||
.orElse(null);
|
||||
if (lastChangeTime != null && lastChangeTime.isAfter(creationTime)) {
|
||||
eventsBuilder.add(makeEvent(EventAction.LAST_CHANGED, null, lastChangeTime));
|
||||
}
|
||||
eventsBuilder.add(makeEvent(EventAction.LAST_UPDATE_OF_RDAP_DATABASE, null, now));
|
||||
eventsBuilder.add(makeEvent(EventAction.LAST_UPDATE_OF_RDAP_DATABASE, null, getRequestTime()));
|
||||
// TODO(b/129849684): sort events by their time once we return a list of Events instead of JSON
|
||||
// objects.
|
||||
return eventsBuilder.build();
|
||||
|
@ -722,7 +675,7 @@ public class RdapJsonFormatter {
|
|||
/**
|
||||
* Creates an event list for a {@link Registrar}.
|
||||
*/
|
||||
private static ImmutableList<Event> makeEvents(Registrar registrar, DateTime now) {
|
||||
private ImmutableList<Event> makeEvents(Registrar registrar) {
|
||||
ImmutableList.Builder<Event> eventsBuilder = new ImmutableList.Builder<>();
|
||||
Long ianaIdentifier = registrar.getIanaIdentifier();
|
||||
eventsBuilder.add(makeEvent(
|
||||
|
@ -734,7 +687,7 @@ public class RdapJsonFormatter {
|
|||
eventsBuilder.add(makeEvent(
|
||||
EventAction.LAST_CHANGED, null, registrar.getLastUpdateTime()));
|
||||
}
|
||||
eventsBuilder.add(makeEvent(EventAction.LAST_UPDATE_OF_RDAP_DATABASE, null, now));
|
||||
eventsBuilder.add(makeEvent(EventAction.LAST_UPDATE_OF_RDAP_DATABASE, null, getRequestTime()));
|
||||
return eventsBuilder.build();
|
||||
}
|
||||
|
||||
|
@ -884,4 +837,26 @@ public class RdapJsonFormatter {
|
|||
.setType("application/rdap+json")
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the DateTime this request took place.
|
||||
*
|
||||
* <p>The RDAP reply is large with a lot of different object in them. We want to make sure that
|
||||
* all these objects are projected to the same "now".
|
||||
*
|
||||
* <p>This "now" will also be considered the time of the "last update of RDAP database" event that
|
||||
* RDAP sepc requires.
|
||||
*
|
||||
* <p>We would have set this during the constructor, but the clock is injected after construction.
|
||||
* So instead we set the time during the first call to this function.
|
||||
*
|
||||
* <p>We would like even more to just inject it in RequestModule and use it in many places in our
|
||||
* codebase that just need a general "now" of the request, but that's a lot of work.
|
||||
*/
|
||||
DateTime getRequestTime() {
|
||||
if (requestTime == null) {
|
||||
requestTime = clock.nowUtc();
|
||||
}
|
||||
return requestTime;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ import google.registry.request.HttpException.NotFoundException;
|
|||
import google.registry.request.auth.Auth;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** RDAP (new WHOIS) action for nameserver requests. */
|
||||
@Action(
|
||||
|
@ -48,7 +47,6 @@ public class RdapNameserverAction extends RdapActionBase {
|
|||
|
||||
@Override
|
||||
public RdapNameserver getJsonObjectForResource(String pathSearchString, boolean isHeadRequest) {
|
||||
DateTime now = clock.nowUtc();
|
||||
pathSearchString = canonicalizeName(pathSearchString);
|
||||
// The RDAP syntax is /rdap/nameserver/ns1.mydomain.com.
|
||||
try {
|
||||
|
@ -63,11 +61,12 @@ public class RdapNameserverAction extends RdapActionBase {
|
|||
// the most recently deleted one.
|
||||
Optional<HostResource> hostResource =
|
||||
loadByForeignKey(
|
||||
HostResource.class, pathSearchString, shouldIncludeDeleted() ? START_OF_TIME : now);
|
||||
if (!shouldBeVisible(hostResource, now)) {
|
||||
HostResource.class,
|
||||
pathSearchString,
|
||||
shouldIncludeDeleted() ? START_OF_TIME : getRequestTime());
|
||||
if (!shouldBeVisible(hostResource)) {
|
||||
throw new NotFoundException(pathSearchString + " not found");
|
||||
}
|
||||
return rdapJsonFormatter.makeRdapJsonForHost(
|
||||
hostResource.get(), rdapWhoisServer, now, OutputDataType.FULL);
|
||||
return rdapJsonFormatter.makeRdapJsonForHost(hostResource.get(), OutputDataType.FULL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,6 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* RDAP (new WHOIS) action for nameserver search requests.
|
||||
|
@ -82,7 +81,6 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
@Override
|
||||
public NameserverSearchResponse getJsonObjectForResource(
|
||||
String pathSearchString, boolean isHeadRequest) {
|
||||
DateTime now = clock.nowUtc();
|
||||
// RDAP syntax example: /rdap/nameservers?name=ns*.example.com.
|
||||
// The pathSearchString is not used by search commands.
|
||||
if (pathSearchString.length() > 0) {
|
||||
|
@ -103,8 +101,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
}
|
||||
results =
|
||||
searchByName(
|
||||
recordWildcardType(RdapSearchPattern.create(Idn.toASCII(nameParam.get()), true)),
|
||||
now);
|
||||
recordWildcardType(RdapSearchPattern.create(Idn.toASCII(nameParam.get()), true)));
|
||||
} else {
|
||||
// syntax: /rdap/nameservers?ip=1.2.3.4
|
||||
metricInformationBuilder.setSearchType(SearchType.BY_NAMESERVER_ADDRESS);
|
||||
|
@ -114,7 +111,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
} catch (IllegalArgumentException e) {
|
||||
throw new BadRequestException("Invalid value of ip parameter");
|
||||
}
|
||||
results = searchByIp(inetAddress, now);
|
||||
results = searchByIp(inetAddress);
|
||||
}
|
||||
if (results.nameserverSearchResults().isEmpty()) {
|
||||
throw new NotFoundException("No nameservers found");
|
||||
|
@ -128,12 +125,11 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
* <p>When deleted nameservers are included in the search, the search is treated as if it has a
|
||||
* wildcard, because multiple results can be returned.
|
||||
*/
|
||||
private NameserverSearchResponse searchByName(
|
||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||
private NameserverSearchResponse searchByName(final RdapSearchPattern partialStringQuery) {
|
||||
// Handle queries without a wildcard -- just load by foreign key. We can't do this if deleted
|
||||
// nameservers are desired, because there may be multiple nameservers with the same name.
|
||||
if (!partialStringQuery.getHasWildcard() && !shouldIncludeDeleted()) {
|
||||
return searchByNameUsingForeignKey(partialStringQuery, now);
|
||||
return searchByNameUsingForeignKey(partialStringQuery);
|
||||
// Handle queries with a wildcard (or including deleted entries). If there is a suffix, it
|
||||
// should be a domain that we manage, so we can look up the domain and search through the
|
||||
// subordinate hosts. This is more efficient, and lets us permit wildcard searches with no
|
||||
|
@ -145,10 +141,10 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
throw new UnprocessableEntityException(
|
||||
"A suffix after a wildcard is not allowed when searching for deleted nameservers");
|
||||
}
|
||||
return searchByNameUsingSuperordinateDomain(partialStringQuery, now);
|
||||
return searchByNameUsingSuperordinateDomain(partialStringQuery);
|
||||
// Handle queries with a wildcard (or deleted entries included), but no suffix.
|
||||
} else {
|
||||
return searchByNameUsingPrefix(partialStringQuery, now);
|
||||
return searchByNameUsingPrefix(partialStringQuery);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,10 +154,11 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
* <p>In this case, we can load by foreign key.
|
||||
*/
|
||||
private NameserverSearchResponse searchByNameUsingForeignKey(
|
||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||
RdapSearchPattern partialStringQuery) {
|
||||
Optional<HostResource> hostResource =
|
||||
loadByForeignKey(HostResource.class, partialStringQuery.getInitialString(), now);
|
||||
if (!shouldBeVisible(hostResource, now)) {
|
||||
loadByForeignKey(
|
||||
HostResource.class, partialStringQuery.getInitialString(), getRequestTime());
|
||||
if (!shouldBeVisible(hostResource)) {
|
||||
metricInformationBuilder.setNumHostsRetrieved(0);
|
||||
throw new NotFoundException("No nameservers found");
|
||||
}
|
||||
|
@ -173,17 +170,15 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
builder.nameserverSearchResultsBuilder().add(
|
||||
rdapJsonFormatter.makeRdapJsonForHost(
|
||||
hostResource.get(),
|
||||
rdapWhoisServer,
|
||||
now,
|
||||
OutputDataType.FULL));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/** Searches for nameservers by name using the superordinate domain as a suffix. */
|
||||
private NameserverSearchResponse searchByNameUsingSuperordinateDomain(
|
||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||
RdapSearchPattern partialStringQuery) {
|
||||
Optional<DomainBase> domainBase =
|
||||
loadByForeignKey(DomainBase.class, partialStringQuery.getSuffix(), now);
|
||||
loadByForeignKey(DomainBase.class, partialStringQuery.getSuffix(), getRequestTime());
|
||||
if (!domainBase.isPresent()) {
|
||||
// Don't allow wildcards with suffixes which are not domains we manage. That would risk a
|
||||
// table scan in many easily foreseeable cases. The user might ask for ns*.zombo.com,
|
||||
|
@ -201,8 +196,9 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
// We can't just check that the host name starts with the initial query string, because
|
||||
// then the query ns.exam*.example.com would match against nameserver ns.example.com.
|
||||
if (partialStringQuery.matches(fqhn)) {
|
||||
Optional<HostResource> hostResource = loadByForeignKey(HostResource.class, fqhn, now);
|
||||
if (shouldBeVisible(hostResource, now)) {
|
||||
Optional<HostResource> hostResource =
|
||||
loadByForeignKey(HostResource.class, fqhn, getRequestTime());
|
||||
if (shouldBeVisible(hostResource)) {
|
||||
hostList.add(hostResource.get());
|
||||
if (hostList.size() > rdapResultSetMaxSize) {
|
||||
break;
|
||||
|
@ -214,8 +210,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
hostList,
|
||||
IncompletenessWarningType.COMPLETE,
|
||||
domainBase.get().getSubordinateHosts().size(),
|
||||
CursorType.NAME,
|
||||
now);
|
||||
CursorType.NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -223,8 +218,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
*
|
||||
* <p>There are no pending deletes for hosts, so we can call {@link RdapActionBase#queryItems}.
|
||||
*/
|
||||
private NameserverSearchResponse searchByNameUsingPrefix(
|
||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||
private NameserverSearchResponse searchByNameUsingPrefix(RdapSearchPattern partialStringQuery) {
|
||||
// Add 1 so we can detect truncation.
|
||||
int querySizeLimit = getStandardQuerySizeLimit();
|
||||
Query<HostResource> query =
|
||||
|
@ -236,13 +230,12 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
getDeletedItemHandling(),
|
||||
querySizeLimit);
|
||||
return makeSearchResults(
|
||||
getMatchingResources(query, shouldIncludeDeleted(), now, querySizeLimit),
|
||||
CursorType.NAME,
|
||||
now);
|
||||
getMatchingResources(query, shouldIncludeDeleted(), querySizeLimit),
|
||||
CursorType.NAME);
|
||||
}
|
||||
|
||||
/** Searches for nameservers by IP address, returning a JSON array of nameserver info maps. */
|
||||
private NameserverSearchResponse searchByIp(final InetAddress inetAddress, DateTime now) {
|
||||
private NameserverSearchResponse searchByIp(InetAddress inetAddress) {
|
||||
// Add 1 so we can detect truncation.
|
||||
int querySizeLimit = getStandardQuerySizeLimit();
|
||||
Query<HostResource> query =
|
||||
|
@ -255,20 +248,18 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
getDeletedItemHandling(),
|
||||
querySizeLimit);
|
||||
return makeSearchResults(
|
||||
getMatchingResources(query, shouldIncludeDeleted(), now, querySizeLimit),
|
||||
CursorType.ADDRESS,
|
||||
now);
|
||||
getMatchingResources(query, shouldIncludeDeleted(), querySizeLimit),
|
||||
CursorType.ADDRESS);
|
||||
}
|
||||
|
||||
/** Output JSON for a lists of hosts contained in an {@link RdapResultSet}. */
|
||||
private NameserverSearchResponse makeSearchResults(
|
||||
RdapResultSet<HostResource> resultSet, CursorType cursorType, DateTime now) {
|
||||
RdapResultSet<HostResource> resultSet, CursorType cursorType) {
|
||||
return makeSearchResults(
|
||||
resultSet.resources(),
|
||||
resultSet.incompletenessWarningType(),
|
||||
resultSet.numResourcesRetrieved(),
|
||||
cursorType,
|
||||
now);
|
||||
cursorType);
|
||||
}
|
||||
|
||||
/** Output JSON for a list of hosts. */
|
||||
|
@ -276,8 +267,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
List<HostResource> hosts,
|
||||
IncompletenessWarningType incompletenessWarningType,
|
||||
int numHostsRetrieved,
|
||||
CursorType cursorType,
|
||||
DateTime now) {
|
||||
CursorType cursorType) {
|
||||
metricInformationBuilder.setNumHostsRetrieved(numHostsRetrieved);
|
||||
OutputDataType outputDataType =
|
||||
(hosts.size() > 1) ? OutputDataType.SUMMARY : OutputDataType.FULL;
|
||||
|
@ -290,9 +280,9 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
(cursorType == CursorType.NAME)
|
||||
? host.getFullyQualifiedHostName()
|
||||
: host.getRepoId());
|
||||
builder.nameserverSearchResultsBuilder().add(
|
||||
rdapJsonFormatter.makeRdapJsonForHost(
|
||||
host, rdapWhoisServer, now, outputDataType));
|
||||
builder
|
||||
.nameserverSearchResultsBuilder()
|
||||
.add(rdapJsonFormatter.makeRdapJsonForHost(host, outputDataType));
|
||||
}
|
||||
if (rdapResultSetMaxSize < hosts.size()) {
|
||||
builder.setNextPageUri(createNavigationUri(newCursor.get()));
|
||||
|
|
|
@ -205,9 +205,18 @@ final class RdapObjectClasses {
|
|||
@JsonableElement abstract ImmutableList<RdapStatus> status();
|
||||
@JsonableElement abstract ImmutableList<Remark> remarks();
|
||||
@JsonableElement abstract ImmutableList<Link> links();
|
||||
@JsonableElement abstract Optional<Port43WhoisServer> port43();
|
||||
@JsonableElement abstract ImmutableList<Event> events();
|
||||
|
||||
/**
|
||||
* WHOIS server displayed in RDAP query responses.
|
||||
*
|
||||
* <p>As per Gustavo Lozano of ICANN, this should be omitted, but the ICANN operational profile
|
||||
* doesn't actually say that, so it's good to have the ability to reinstate this field if
|
||||
* necessary.
|
||||
*/
|
||||
@JsonableElement
|
||||
abstract Optional<Port43WhoisServer> port43();
|
||||
|
||||
RdapObjectBase(BoilerplateType boilerplateType, ObjectClassName objectClassName) {
|
||||
super(boilerplateType);
|
||||
this.objectClassName = objectClassName;
|
||||
|
|
|
@ -17,6 +17,7 @@ package google.registry.request;
|
|||
import static com.google.common.net.MediaType.JSON_UTF_8;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.VerifyException;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.io.ByteStreams;
|
||||
|
@ -47,6 +48,7 @@ public final class RequestModule {
|
|||
private final HttpServletResponse rsp;
|
||||
private final AuthResult authResult;
|
||||
|
||||
@VisibleForTesting
|
||||
public RequestModule(
|
||||
HttpServletRequest req, HttpServletResponse rsp) {
|
||||
this(req, rsp, AuthResult.NOT_AUTHENTICATED);
|
||||
|
|
|
@ -73,7 +73,6 @@ public class RdapActionBaseTest extends RdapActionBaseTestCase<RdapActionBaseTes
|
|||
@Before
|
||||
public void setUp() {
|
||||
createTld("thing");
|
||||
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -89,15 +89,13 @@ public class RdapActionBaseTestCase<A extends RdapActionBase> {
|
|||
public void baseSetUp() {
|
||||
inject.setStaticField(Ofy.class, "clock", clock);
|
||||
action = TypeUtils.instantiate(rdapActionClass);
|
||||
action.clock = clock;
|
||||
action.includeDeletedParam = Optional.empty();
|
||||
action.registrarParam = Optional.empty();
|
||||
action.formatOutputParam = Optional.empty();
|
||||
action.response = response;
|
||||
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
||||
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter(clock);
|
||||
action.rdapMetrics = rdapMetrics;
|
||||
action.requestMethod = Action.Method.GET;
|
||||
action.rdapWhoisServer = null;
|
||||
logout();
|
||||
}
|
||||
|
||||
|
|
|
@ -86,14 +86,12 @@ public class RdapJsonFormatterTest {
|
|||
private ContactResource contactResourceTech;
|
||||
private ContactResource contactResourceNotLinked;
|
||||
|
||||
// Do not set a port43 whois server, as per Gustavo Lozano.
|
||||
private static final String WHOIS_SERVER = null;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
inject.setStaticField(Ofy.class, "clock", clock);
|
||||
|
||||
rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
||||
rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter(clock);
|
||||
rdapJsonFormatter.rdapAuthorization =
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar");
|
||||
|
||||
|
@ -315,51 +313,35 @@ public class RdapJsonFormatterTest {
|
|||
|
||||
@Test
|
||||
public void testRegistrar() {
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForRegistrar(
|
||||
registrar, WHOIS_SERVER, clock.nowUtc(), OutputDataType.FULL)
|
||||
.toJson())
|
||||
assertThat(rdapJsonFormatter.makeRdapJsonForRegistrar(registrar, OutputDataType.FULL).toJson())
|
||||
.isEqualTo(loadJson("rdapjson_registrar.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegistrar_summary() {
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForRegistrar(
|
||||
registrar, WHOIS_SERVER, clock.nowUtc(), OutputDataType.SUMMARY)
|
||||
.toJson())
|
||||
rdapJsonFormatter.makeRdapJsonForRegistrar(registrar, OutputDataType.SUMMARY).toJson())
|
||||
.isEqualTo(loadJson("rdapjson_registrar_summary.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHost_ipv4() {
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForHost(
|
||||
hostResourceIpv4, WHOIS_SERVER, clock.nowUtc(), OutputDataType.FULL)
|
||||
.toJson())
|
||||
rdapJsonFormatter.makeRdapJsonForHost(hostResourceIpv4, OutputDataType.FULL).toJson())
|
||||
.isEqualTo(loadJson("rdapjson_host_ipv4.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHost_ipv6() {
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForHost(
|
||||
hostResourceIpv6, WHOIS_SERVER, clock.nowUtc(), OutputDataType.FULL)
|
||||
.toJson())
|
||||
rdapJsonFormatter.makeRdapJsonForHost(hostResourceIpv6, OutputDataType.FULL).toJson())
|
||||
.isEqualTo(loadJson("rdapjson_host_ipv6.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHost_both() {
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForHost(
|
||||
hostResourceBoth, WHOIS_SERVER, clock.nowUtc(), OutputDataType.FULL)
|
||||
.toJson())
|
||||
rdapJsonFormatter.makeRdapJsonForHost(hostResourceBoth, OutputDataType.FULL).toJson())
|
||||
.isEqualTo(loadJson("rdapjson_host_both.json"));
|
||||
}
|
||||
|
||||
|
@ -367,8 +349,7 @@ public class RdapJsonFormatterTest {
|
|||
public void testHost_both_summary() {
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForHost(
|
||||
hostResourceBoth, WHOIS_SERVER, clock.nowUtc(), OutputDataType.SUMMARY)
|
||||
.makeRdapJsonForHost(hostResourceBoth, OutputDataType.SUMMARY)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_host_both_summary.json"));
|
||||
}
|
||||
|
@ -377,8 +358,7 @@ public class RdapJsonFormatterTest {
|
|||
public void testHost_noAddresses() {
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForHost(
|
||||
hostResourceNoAddresses, WHOIS_SERVER, clock.nowUtc(), OutputDataType.FULL)
|
||||
.makeRdapJsonForHost(hostResourceNoAddresses, OutputDataType.FULL)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_host_no_addresses.json"));
|
||||
}
|
||||
|
@ -387,8 +367,7 @@ public class RdapJsonFormatterTest {
|
|||
public void testHost_notLinked() {
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForHost(
|
||||
hostResourceNotLinked, WHOIS_SERVER, clock.nowUtc(), OutputDataType.FULL)
|
||||
.makeRdapJsonForHost(hostResourceNotLinked, OutputDataType.FULL)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_host_not_linked.json"));
|
||||
}
|
||||
|
@ -397,11 +376,7 @@ public class RdapJsonFormatterTest {
|
|||
public void testHost_superordinateHasPendingTransfer() {
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForHost(
|
||||
hostResourceSuperordinatePendingTransfer,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL)
|
||||
.makeRdapJsonForHost(hostResourceSuperordinatePendingTransfer, OutputDataType.FULL)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_host_pending_transfer.json"));
|
||||
}
|
||||
|
@ -413,8 +388,6 @@ public class RdapJsonFormatterTest {
|
|||
.makeRdapJsonForContact(
|
||||
contactResourceRegistrant,
|
||||
Optional.of(DesignatedContact.Type.REGISTRANT),
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_registrant.json"));
|
||||
|
@ -427,8 +400,6 @@ public class RdapJsonFormatterTest {
|
|||
.makeRdapJsonForContact(
|
||||
contactResourceRegistrant,
|
||||
Optional.of(DesignatedContact.Type.REGISTRANT),
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.SUMMARY)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_registrant_summary.json"));
|
||||
|
@ -442,8 +413,6 @@ public class RdapJsonFormatterTest {
|
|||
.makeRdapJsonForContact(
|
||||
contactResourceRegistrant,
|
||||
Optional.of(DesignatedContact.Type.REGISTRANT),
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_registrant_logged_out.json"));
|
||||
|
@ -463,8 +432,6 @@ public class RdapJsonFormatterTest {
|
|||
.makeRdapJsonForContact(
|
||||
contactResourceRegistrant,
|
||||
Optional.of(DesignatedContact.Type.REGISTRANT),
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_registrant.json"));
|
||||
|
@ -477,8 +444,6 @@ public class RdapJsonFormatterTest {
|
|||
.makeRdapJsonForContact(
|
||||
contactResourceAdmin,
|
||||
Optional.of(DesignatedContact.Type.ADMIN),
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_admincontact.json"));
|
||||
|
@ -491,8 +456,6 @@ public class RdapJsonFormatterTest {
|
|||
.makeRdapJsonForContact(
|
||||
contactResourceTech,
|
||||
Optional.of(DesignatedContact.Type.TECH),
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_techcontact.json"));
|
||||
|
@ -505,8 +468,6 @@ public class RdapJsonFormatterTest {
|
|||
.makeRdapJsonForContact(
|
||||
contactResourceTech,
|
||||
Optional.empty(),
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_rolelesscontact.json"));
|
||||
|
@ -519,8 +480,6 @@ public class RdapJsonFormatterTest {
|
|||
.makeRdapJsonForContact(
|
||||
contactResourceNotLinked,
|
||||
Optional.empty(),
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_unlinkedcontact.json"));
|
||||
|
@ -532,8 +491,6 @@ public class RdapJsonFormatterTest {
|
|||
rdapJsonFormatter
|
||||
.makeRdapJsonForDomain(
|
||||
domainBaseFull,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_domain_full.json"));
|
||||
|
@ -543,11 +500,7 @@ public class RdapJsonFormatterTest {
|
|||
public void testDomain_summary() {
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForDomain(
|
||||
domainBaseFull,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.SUMMARY)
|
||||
.makeRdapJsonForDomain(domainBaseFull, OutputDataType.SUMMARY)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_domain_summary.json"));
|
||||
}
|
||||
|
@ -556,13 +509,7 @@ public class RdapJsonFormatterTest {
|
|||
public void testDomain_logged_out() {
|
||||
rdapJsonFormatter.rdapAuthorization = RdapAuthorization.PUBLIC_AUTHORIZATION;
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForDomain(
|
||||
domainBaseFull,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL)
|
||||
.toJson())
|
||||
rdapJsonFormatter.makeRdapJsonForDomain(domainBaseFull, OutputDataType.FULL).toJson())
|
||||
.isEqualTo(loadJson("rdapjson_domain_logged_out.json"));
|
||||
}
|
||||
|
||||
|
@ -570,11 +517,7 @@ public class RdapJsonFormatterTest {
|
|||
public void testDomain_noNameserversNoTransfers() {
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForDomain(
|
||||
domainBaseNoNameserversNoTransfers,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL)
|
||||
.makeRdapJsonForDomain(domainBaseNoNameserversNoTransfers, OutputDataType.FULL)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_domain_no_nameservers.json"));
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import com.google.gson.GsonBuilder;
|
|||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import google.registry.util.Clock;
|
||||
|
||||
public class RdapTestHelper {
|
||||
|
||||
|
@ -142,10 +143,11 @@ public class RdapTestHelper {
|
|||
"type", "text/html")))));
|
||||
}
|
||||
|
||||
static RdapJsonFormatter getTestRdapJsonFormatter() {
|
||||
static RdapJsonFormatter getTestRdapJsonFormatter(Clock clock) {
|
||||
RdapJsonFormatter rdapJsonFormatter = new RdapJsonFormatter();
|
||||
rdapJsonFormatter.rdapAuthorization = RdapAuthorization.PUBLIC_AUTHORIZATION;
|
||||
rdapJsonFormatter.fullServletPath = "https://example.tld/rdap/";
|
||||
rdapJsonFormatter.clock = clock;
|
||||
rdapJsonFormatter.rdapTos =
|
||||
ImmutableList.of(
|
||||
"By querying our Domain Database, you are agreeing to comply with these"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue