mirror of
https://github.com/google/nomulus.git
synced 2025-05-29 17:00:11 +02:00
Add RDAP support for deleted domains and filtering by registrar
This CL adds the functionality for domain searches. Entities and nameservers have already been handled by previous CLs. Deleted items can only be seen by admins, and by registrars viewing their own deleted items. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=172097922
This commit is contained in:
parent
048ae4b4ba
commit
03087ddc85
9 changed files with 769 additions and 281 deletions
|
@ -26,6 +26,7 @@
|
||||||
<datastore-index kind="HostResource" ancestor="false" source="manual">
|
<datastore-index kind="HostResource" ancestor="false" source="manual">
|
||||||
<property name="currentSponsorClientId" direction="asc"/>
|
<property name="currentSponsorClientId" direction="asc"/>
|
||||||
<property name="deletionTime" direction="asc"/>
|
<property name="deletionTime" direction="asc"/>
|
||||||
|
<property name="fullyQualifiedHostName" direction="asc"/>
|
||||||
</datastore-index>
|
</datastore-index>
|
||||||
<!-- For finding account balance of registrar and viewing billing history. -->
|
<!-- For finding account balance of registrar and viewing billing history. -->
|
||||||
<datastore-index kind="RegistrarBillingEntry" ancestor="true" source="manual">
|
<datastore-index kind="RegistrarBillingEntry" ancestor="true" source="manual">
|
||||||
|
@ -71,6 +72,11 @@
|
||||||
<property name="^i" direction="asc"/>
|
<property name="^i" direction="asc"/>
|
||||||
<property name="fullyQualifiedDomainName" direction="asc"/>
|
<property name="fullyQualifiedDomainName" direction="asc"/>
|
||||||
</datastore-index>
|
</datastore-index>
|
||||||
|
<datastore-index kind="DomainBase" ancestor="false" source="manual">
|
||||||
|
<property name="^i" direction="asc"/>
|
||||||
|
<property name="currentSponsorClientId" direction="asc"/>
|
||||||
|
<property name="fullyQualifiedDomainName" direction="asc"/>
|
||||||
|
</datastore-index>
|
||||||
<datastore-index kind="DomainBase" ancestor="false" source="manual">
|
<datastore-index kind="DomainBase" ancestor="false" source="manual">
|
||||||
<property name="^i" direction="asc"/>
|
<property name="^i" direction="asc"/>
|
||||||
<property name="tld" direction="asc"/>
|
<property name="tld" direction="asc"/>
|
||||||
|
|
|
@ -215,16 +215,28 @@ public abstract class RdapActionBase implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the EPP resource should be visible. This is true iff:
|
* Returns true if the request is authorized to see the resource.
|
||||||
|
*
|
||||||
|
* <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())
|
||||||
|
|| (shouldIncludeDeleted()
|
||||||
|
&& getAuthorization()
|
||||||
|
.isAuthorizedForClientId(eppResource.getPersistedCurrentSponsorClientId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the EPP resource should be visible.
|
||||||
|
*
|
||||||
|
* <p>This is true iff:
|
||||||
* 1. The resource is not deleted, or the request wants to see deleted items, and is authorized to
|
* 1. The resource is not deleted, or the request wants to see deleted items, and is authorized to
|
||||||
* do so, and:
|
* do so, and:
|
||||||
* 2. The request did not specify a registrar to filter on, or the registrar matches.
|
* 2. The request did not specify a registrar to filter on, or the registrar matches.
|
||||||
*/
|
*/
|
||||||
boolean shouldBeVisible(EppResource eppResource, DateTime now) {
|
boolean shouldBeVisible(EppResource eppResource, DateTime now) {
|
||||||
return (now.isBefore(eppResource.getDeletionTime())
|
return isAuthorized(eppResource, now)
|
||||||
|| (shouldIncludeDeleted()
|
|
||||||
&& getAuthorization()
|
|
||||||
.isAuthorizedForClientId(eppResource.getPersistedCurrentSponsorClientId())))
|
|
||||||
&& (!registrarParam.isPresent()
|
&& (!registrarParam.isPresent()
|
||||||
|| registrarParam.get().equals(eppResource.getPersistedCurrentSponsorClientId()));
|
|| registrarParam.get().equals(eppResource.getPersistedCurrentSponsorClientId()));
|
||||||
}
|
}
|
||||||
|
@ -366,6 +378,11 @@ public abstract class RdapActionBase implements Runnable {
|
||||||
* @param query an already-defined query to be run; a filter on currentSponsorClientId will be
|
* @param query an already-defined query to be run; a filter on currentSponsorClientId will be
|
||||||
* added if appropriate
|
* added if appropriate
|
||||||
* @param now the time as of which to evaluate the query
|
* @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
|
||||||
|
* limit of one field queried for inequality, for instance), it may need to be set to true
|
||||||
|
* even when not including deleted records
|
||||||
* @return an {@link RdapResourcesAndIncompletenessWarningType} object containing the list of
|
* @return an {@link RdapResourcesAndIncompletenessWarningType} object containing the list of
|
||||||
* resources and an incompleteness warning flag, which is set to MIGHT_BE_INCOMPLETE iff
|
* resources and an incompleteness warning flag, which is set to MIGHT_BE_INCOMPLETE iff
|
||||||
* any resources were excluded due to lack of visibility, and the resulting list of
|
* any resources were excluded due to lack of visibility, and the resulting list of
|
||||||
|
@ -373,12 +390,12 @@ public abstract class RdapActionBase implements Runnable {
|
||||||
* fetched enough resources
|
* fetched enough resources
|
||||||
*/
|
*/
|
||||||
<T extends EppResource> RdapResourcesAndIncompletenessWarningType<T> getMatchingResources(
|
<T extends EppResource> RdapResourcesAndIncompletenessWarningType<T> getMatchingResources(
|
||||||
Query<T> query, DateTime now) {
|
Query<T> query, boolean checkForVisibility, DateTime now) {
|
||||||
Optional<String> desiredRegistrar = getDesiredRegistrar();
|
Optional<String> desiredRegistrar = getDesiredRegistrar();
|
||||||
if (desiredRegistrar.isPresent()) {
|
if (desiredRegistrar.isPresent()) {
|
||||||
query = query.filter("currentSponsorClientId", desiredRegistrar.get());
|
query = query.filter("currentSponsorClientId", desiredRegistrar.get());
|
||||||
}
|
}
|
||||||
if (!shouldIncludeDeleted()) {
|
if (!checkForVisibility) {
|
||||||
return RdapResourcesAndIncompletenessWarningType.create(query.list());
|
return RdapResourcesAndIncompletenessWarningType.create(query.list());
|
||||||
}
|
}
|
||||||
// If we are including deleted resources, we need to check that we're authorized for each one.
|
// If we are including deleted resources, we need to check that we're authorized for each one.
|
||||||
|
|
|
@ -18,6 +18,7 @@ import static google.registry.flows.domain.DomainFlowUtils.validateDomainName;
|
||||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
||||||
import static google.registry.request.Action.Method.GET;
|
import static google.registry.request.Action.Method.GET;
|
||||||
import static google.registry.request.Action.Method.HEAD;
|
import static google.registry.request.Action.Method.HEAD;
|
||||||
|
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import google.registry.flows.EppException;
|
import google.registry.flows.EppException;
|
||||||
|
@ -69,8 +70,10 @@ public class RdapDomainAction extends RdapActionBase {
|
||||||
pathSearchString, getHumanReadableObjectTypeName(), e.getMessage()));
|
pathSearchString, getHumanReadableObjectTypeName(), e.getMessage()));
|
||||||
}
|
}
|
||||||
// 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.
|
||||||
DomainResource domainResource = loadByForeignKey(DomainResource.class, pathSearchString, now);
|
DomainResource domainResource =
|
||||||
if (domainResource == null) {
|
loadByForeignKey(
|
||||||
|
DomainResource.class, pathSearchString, shouldIncludeDeleted() ? START_OF_TIME : now);
|
||||||
|
if ((domainResource == null) || !shouldBeVisible(domainResource, now)) {
|
||||||
throw new NotFoundException(pathSearchString + " not found");
|
throw new NotFoundException(pathSearchString + " not found");
|
||||||
}
|
}
|
||||||
return rdapJsonFormatter.makeRdapJsonForDomain(
|
return rdapJsonFormatter.makeRdapJsonForDomain(
|
||||||
|
|
|
@ -19,7 +19,7 @@ import static google.registry.model.index.ForeignKeyIndex.loadAndGetKey;
|
||||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||||
import static google.registry.request.Action.Method.GET;
|
import static google.registry.request.Action.Method.GET;
|
||||||
import static google.registry.request.Action.Method.HEAD;
|
import static google.registry.request.Action.Method.HEAD;
|
||||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
@ -28,7 +28,6 @@ import com.google.common.collect.Iterables;
|
||||||
import com.google.common.primitives.Booleans;
|
import com.google.common.primitives.Booleans;
|
||||||
import com.googlecode.objectify.Key;
|
import com.googlecode.objectify.Key;
|
||||||
import com.googlecode.objectify.cmd.Query;
|
import com.googlecode.objectify.cmd.Query;
|
||||||
import google.registry.model.EppResourceUtils;
|
|
||||||
import google.registry.model.domain.DomainResource;
|
import google.registry.model.domain.DomainResource;
|
||||||
import google.registry.model.host.HostResource;
|
import google.registry.model.host.HostResource;
|
||||||
import google.registry.rdap.RdapJsonFormatter.BoilerplateType;
|
import google.registry.rdap.RdapJsonFormatter.BoilerplateType;
|
||||||
|
@ -156,33 +155,20 @@ public class RdapDomainSearchAction extends RdapActionBase {
|
||||||
* characters (e.g. "ex*"), to avoid queries for all domains in the system. If the TLD is present,
|
* characters (e.g. "ex*"), to avoid queries for all domains in the system. If the TLD is present,
|
||||||
* the initial string is not required (e.g. "*.tld" is valid), because the search will be
|
* the initial string is not required (e.g. "*.tld" is valid), because the search will be
|
||||||
* restricted to a single TLD.
|
* restricted to a single TLD.
|
||||||
|
*
|
||||||
|
* <p>Searches which include deleted entries are effectively treated as if they have a wildcard,
|
||||||
|
* since the same name can return multiple results.
|
||||||
*/
|
*/
|
||||||
private RdapSearchResults searchByDomainName(
|
private RdapSearchResults searchByDomainName(
|
||||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||||
// Handle queries without a wildcard -- just load by foreign key.
|
// Handle queries without a wildcard -- just load by foreign key. We can't do this if deleted
|
||||||
if (!partialStringQuery.getHasWildcard()) {
|
// entries are included, because there may be multiple nameservers with the same name.
|
||||||
DomainResource domainResource =
|
if (!partialStringQuery.getHasWildcard() && !shouldIncludeDeleted()) {
|
||||||
loadByForeignKey(DomainResource.class, partialStringQuery.getInitialString(), now);
|
return searchByDomainNameWithoutWildcard(partialStringQuery, now);
|
||||||
ImmutableList<DomainResource> results = (domainResource == null)
|
}
|
||||||
? ImmutableList.<DomainResource>of()
|
// Handle queries with a wildcard and initial search string. We require either a TLD or an
|
||||||
: ImmutableList.of(domainResource);
|
// initial string at least MIN_INITIAL_STRING_LENGTH long.
|
||||||
return makeSearchResults(results, now);
|
if (!partialStringQuery.getInitialString().isEmpty()) {
|
||||||
// Handle queries with a wildcard and no initial string.
|
|
||||||
} else if (partialStringQuery.getInitialString().isEmpty()) {
|
|
||||||
if (partialStringQuery.getSuffix() == null) {
|
|
||||||
throw new UnprocessableEntityException(
|
|
||||||
"Initial search string is required for wildcard domain searches without a TLD suffix");
|
|
||||||
}
|
|
||||||
// Since we aren't searching on fullyQualifiedDomainName, we can perform our one allowed
|
|
||||||
// inequality query on deletion time.
|
|
||||||
Query<DomainResource> query = ofy().load()
|
|
||||||
.type(DomainResource.class)
|
|
||||||
.filter("tld", partialStringQuery.getSuffix())
|
|
||||||
.filter("deletionTime >", now)
|
|
||||||
.limit(rdapResultSetMaxSize + 1);
|
|
||||||
return makeSearchResults(query.list(), now);
|
|
||||||
// Handle queries with a wildcard and an initial string.
|
|
||||||
} else {
|
|
||||||
if ((partialStringQuery.getSuffix() == null)
|
if ((partialStringQuery.getSuffix() == null)
|
||||||
&& (partialStringQuery.getInitialString().length()
|
&& (partialStringQuery.getInitialString().length()
|
||||||
< RdapSearchPattern.MIN_INITIAL_STRING_LENGTH)) {
|
< RdapSearchPattern.MIN_INITIAL_STRING_LENGTH)) {
|
||||||
|
@ -192,44 +178,64 @@ public class RdapDomainSearchAction extends RdapActionBase {
|
||||||
+ " without a TLD suffix",
|
+ " without a TLD suffix",
|
||||||
RdapSearchPattern.MIN_INITIAL_STRING_LENGTH));
|
RdapSearchPattern.MIN_INITIAL_STRING_LENGTH));
|
||||||
}
|
}
|
||||||
|
return searchByDomainNameWithInitialString(partialStringQuery, now);
|
||||||
// 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
|
|
||||||
// RESULT_SET_SIZE_SCALING_FACTOR times the result set size limit, fetch up to that many, and
|
|
||||||
// weed out all deleted domains. If there still isn't a full result set's worth of domains, we
|
|
||||||
// give up and return just the ones we found.
|
|
||||||
// TODO(b/31546493): Add metrics to figure out how well this works.
|
|
||||||
List<DomainResource> domainList = new ArrayList<>();
|
|
||||||
Query<DomainResource> query = ofy().load()
|
|
||||||
.type(DomainResource.class)
|
|
||||||
.filter("fullyQualifiedDomainName <", partialStringQuery.getNextInitialString())
|
|
||||||
.filter("fullyQualifiedDomainName >=", partialStringQuery.getInitialString());
|
|
||||||
if (partialStringQuery.getSuffix() != null) {
|
|
||||||
query = query.filter("tld", partialStringQuery.getSuffix());
|
|
||||||
}
|
|
||||||
// Query the domains directly, rather than the foreign keys, because then we have an index on
|
|
||||||
// TLD if we need it.
|
|
||||||
int numFetched = 0;
|
|
||||||
for (DomainResource domain :
|
|
||||||
query.limit(RESULT_SET_SIZE_SCALING_FACTOR * rdapResultSetMaxSize)) {
|
|
||||||
numFetched++;
|
|
||||||
if (EppResourceUtils.isActive(domain, now)) {
|
|
||||||
if (domainList.size() >= rdapResultSetMaxSize) {
|
|
||||||
return makeSearchResults(
|
|
||||||
ImmutableList.copyOf(domainList), IncompletenessWarningType.TRUNCATED, now);
|
|
||||||
}
|
|
||||||
domainList.add(domain);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return makeSearchResults(
|
|
||||||
domainList,
|
|
||||||
((numFetched == RESULT_SET_SIZE_SCALING_FACTOR * rdapResultSetMaxSize)
|
|
||||||
&& (domainList.size() < rdapResultSetMaxSize))
|
|
||||||
? IncompletenessWarningType.MIGHT_BE_INCOMPLETE
|
|
||||||
: IncompletenessWarningType.NONE,
|
|
||||||
now);
|
|
||||||
}
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for domains by domain name without a wildcard or interest in deleted entries.
|
||||||
|
*/
|
||||||
|
private RdapSearchResults searchByDomainNameWithoutWildcard(
|
||||||
|
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||||
|
DomainResource domainResource =
|
||||||
|
loadByForeignKey(DomainResource.class, partialStringQuery.getInitialString(), now);
|
||||||
|
ImmutableList<DomainResource> results =
|
||||||
|
((domainResource == null) || !shouldBeVisible(domainResource, now))
|
||||||
|
? ImmutableList.<DomainResource>of()
|
||||||
|
: ImmutableList.of(domainResource);
|
||||||
|
return makeSearchResults(results, now);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Searches for domains by domain name with an initial string, wildcard and possible suffix. */
|
||||||
|
private RdapSearchResults searchByDomainNameWithInitialString(
|
||||||
|
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||||
|
// 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
|
||||||
|
// RESULT_SET_SIZE_SCALING_FACTOR times the result set size limit, fetch up to that many, and
|
||||||
|
// weed out all deleted domains. If there still isn't a full result set's worth of domains, we
|
||||||
|
// give up and return just the ones we found. Don't use queryItems, because it checks that the
|
||||||
|
// initial string is at least a certain length, which we don't need in this case. Query the
|
||||||
|
// domains directly, rather than the foreign keys, because then we have an index on TLD if we
|
||||||
|
// need it.
|
||||||
|
// TODO(b/31546493): Add metrics to figure out how well this works.
|
||||||
|
Query<DomainResource> query =
|
||||||
|
ofy()
|
||||||
|
.load()
|
||||||
|
.type(DomainResource.class)
|
||||||
|
.filter("fullyQualifiedDomainName <", partialStringQuery.getNextInitialString())
|
||||||
|
.filter("fullyQualifiedDomainName >=", partialStringQuery.getInitialString())
|
||||||
|
.limit(RESULT_SET_SIZE_SCALING_FACTOR * rdapResultSetMaxSize);
|
||||||
|
if (partialStringQuery.getSuffix() != null) {
|
||||||
|
query = query.filter("tld", partialStringQuery.getSuffix());
|
||||||
|
}
|
||||||
|
// Always check for visibility, because we couldn't look at the deletionTime in the query.
|
||||||
|
return makeSearchResults(getMatchingResources(query, true, now), now);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Searches for domains by domain name with a TLD suffix. */
|
||||||
|
private RdapSearchResults searchByDomainNameByTld(String tld, DateTime now) {
|
||||||
|
// Since we aren't searching on fullyQualifiedDomainName, we can perform our one allowed
|
||||||
|
// inequality query on deletion time.
|
||||||
|
Query<DomainResource> query =
|
||||||
|
queryItems(
|
||||||
|
DomainResource.class, "tld", tld, shouldIncludeDeleted(), rdapResultSetMaxSize + 1);
|
||||||
|
return makeSearchResults(getMatchingResources(query, shouldIncludeDeleted(), now), now);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -237,6 +243,9 @@ public class RdapDomainSearchAction extends RdapActionBase {
|
||||||
*
|
*
|
||||||
* <p>This is a two-step process: get a list of host references by host name, and then look up
|
* <p>This is a two-step process: get a list of host references by host name, and then look up
|
||||||
* domains by host reference.
|
* domains by host reference.
|
||||||
|
*
|
||||||
|
* <p>The includeDeleted parameter does NOT cause deleted nameservers to be searched, only deleted
|
||||||
|
* domains which used to be connected to an undeleted nameserver.
|
||||||
*/
|
*/
|
||||||
private RdapSearchResults searchByNameserverLdhName(
|
private RdapSearchResults searchByNameserverLdhName(
|
||||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||||
|
@ -259,62 +268,106 @@ public class RdapDomainSearchAction extends RdapActionBase {
|
||||||
*/
|
*/
|
||||||
private Iterable<Key<HostResource>> getNameserverRefsByLdhName(
|
private Iterable<Key<HostResource>> getNameserverRefsByLdhName(
|
||||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||||
// Handle queries without a wildcard; just load the host by foreign key in the usual way.
|
// Handle queries without a wildcard.
|
||||||
if (!partialStringQuery.getHasWildcard()) {
|
if (!partialStringQuery.getHasWildcard()) {
|
||||||
Key<HostResource> hostKey = loadAndGetKey(
|
return getNameserverRefsByLdhNameWithoutWildcard(partialStringQuery, now);
|
||||||
HostResource.class, partialStringQuery.getInitialString(), now);
|
}
|
||||||
if (hostKey == null) {
|
// Handle queries with a wildcard and suffix (specifying a suprerordinate domain).
|
||||||
return ImmutableList.of();
|
if (partialStringQuery.getSuffix() != null) {
|
||||||
} else {
|
return getNameserverRefsByLdhNameWithSuffix(partialStringQuery, now);
|
||||||
return ImmutableList.of(hostKey);
|
}
|
||||||
}
|
// If there's no suffix, query the host resources. Query the resources themselves, rather than
|
||||||
// Handle queries with a wildcard.
|
// the foreign key indexes, because then we have an index on fully qualified host name and
|
||||||
|
// deletion time, so we can check the deletion status in the query itself. The initial string
|
||||||
|
// must be present, to avoid querying every host in the system. This restriction is enforced by
|
||||||
|
// {@link queryItems}.
|
||||||
|
//
|
||||||
|
// Only return the first 1000 nameservers. This could result in an incomplete result set if
|
||||||
|
// a search asks for something like "ns*", but we need to enforce a limit in order to avoid
|
||||||
|
// arbitrarily long-running queries.
|
||||||
|
Query<HostResource> query =
|
||||||
|
queryItems(
|
||||||
|
HostResource.class,
|
||||||
|
"fullyQualifiedHostName",
|
||||||
|
partialStringQuery,
|
||||||
|
false, /* includeDeleted */
|
||||||
|
MAX_NAMESERVERS_IN_FIRST_STAGE);
|
||||||
|
Optional<String> desiredRegistrar = getDesiredRegistrar();
|
||||||
|
if (desiredRegistrar.isPresent()) {
|
||||||
|
query = query.filter("currentSponsorClientId", desiredRegistrar.get());
|
||||||
|
}
|
||||||
|
return query.keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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) {
|
||||||
|
// If we need to check the sponsoring registrar, we need to load the resource rather than just
|
||||||
|
// the key.
|
||||||
|
Optional<String> desiredRegistrar = getDesiredRegistrar();
|
||||||
|
if (desiredRegistrar.isPresent()) {
|
||||||
|
HostResource host =
|
||||||
|
loadByForeignKey(
|
||||||
|
HostResource.class,
|
||||||
|
partialStringQuery.getInitialString(),
|
||||||
|
shouldIncludeDeleted() ? START_OF_TIME : now);
|
||||||
|
return ((host == null)
|
||||||
|
|| !desiredRegistrar.get().equals(host.getPersistedCurrentSponsorClientId()))
|
||||||
|
? ImmutableList.of()
|
||||||
|
: ImmutableList.of(Key.create(host));
|
||||||
} else {
|
} else {
|
||||||
// If there is a suffix, it must be a domain that we manage. That way, we can look up the
|
Key<HostResource> hostKey =
|
||||||
// domain and search through the subordinate hosts. This is more efficient, and lets us permit
|
loadAndGetKey(
|
||||||
// wildcard searches with no initial string.
|
HostResource.class,
|
||||||
if (partialStringQuery.getSuffix() != null) {
|
partialStringQuery.getInitialString(),
|
||||||
DomainResource domainResource = loadByForeignKey(
|
shouldIncludeDeleted() ? START_OF_TIME : now);
|
||||||
DomainResource.class, partialStringQuery.getSuffix(), now);
|
return (hostKey == null) ? ImmutableList.of() : ImmutableList.of(hostKey);
|
||||||
if (domainResource == null) {
|
}
|
||||||
// Don't allow wildcards with suffixes which are not domains we manage. That would risk a
|
}
|
||||||
// table scan in some easily foreseeable cases.
|
|
||||||
throw new UnprocessableEntityException(
|
/** Assembles a list of {@link HostResource} keys by name using a superordinate domain suffix. */
|
||||||
"A suffix in a lookup by nameserver name must be an in-bailiwick domain");
|
private Iterable<Key<HostResource>> getNameserverRefsByLdhNameWithSuffix(
|
||||||
}
|
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||||
ImmutableList.Builder<Key<HostResource>> builder = new ImmutableList.Builder<>();
|
// The suffix must be a domain that we manage. That way, we can look up the domain and search
|
||||||
for (String fqhn : ImmutableSortedSet.copyOf(domainResource.getSubordinateHosts())) {
|
// through the subordinate hosts. This is more efficient, and lets us permit wildcard searches
|
||||||
// We can't just check that the host name starts with the initial query string, because
|
// with no initial string.
|
||||||
// then the query ns.exam*.example.com would match against nameserver ns.example.com.
|
DomainResource domainResource =
|
||||||
if (partialStringQuery.matches(fqhn)) {
|
loadByForeignKey(
|
||||||
Key<HostResource> hostKey = loadAndGetKey(HostResource.class, fqhn, now);
|
DomainResource.class,
|
||||||
if (hostKey != null) {
|
partialStringQuery.getSuffix(),
|
||||||
builder.add(hostKey);
|
shouldIncludeDeleted() ? START_OF_TIME : now);
|
||||||
} else {
|
if (domainResource == null) {
|
||||||
logger.warningfmt("Host key unexpectedly null");
|
// Don't allow wildcards with suffixes which are not domains we manage. That would risk a
|
||||||
}
|
// table scan in some easily foreseeable cases.
|
||||||
|
throw new UnprocessableEntityException(
|
||||||
|
"A suffix in a lookup by nameserver name must be a domain defined in the system");
|
||||||
|
}
|
||||||
|
Optional<String> desiredRegistrar = getDesiredRegistrar();
|
||||||
|
ImmutableList.Builder<Key<HostResource>> builder = new ImmutableList.Builder<>();
|
||||||
|
for (String fqhn : ImmutableSortedSet.copyOf(domainResource.getSubordinateHosts())) {
|
||||||
|
// 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)) {
|
||||||
|
if (desiredRegistrar.isPresent()) {
|
||||||
|
HostResource host =
|
||||||
|
loadByForeignKey(
|
||||||
|
HostResource.class, fqhn, shouldIncludeDeleted() ? START_OF_TIME : now);
|
||||||
|
if ((host != null)
|
||||||
|
&& desiredRegistrar.get().equals(host.getPersistedCurrentSponsorClientId())) {
|
||||||
|
builder.add(Key.create(host));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Key<HostResource> hostKey =
|
||||||
|
loadAndGetKey(HostResource.class, fqhn, shouldIncludeDeleted() ? START_OF_TIME : now);
|
||||||
|
if (hostKey != null) {
|
||||||
|
builder.add(hostKey);
|
||||||
|
} else {
|
||||||
|
logger.warningfmt("Host key unexpectedly null");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return builder.build();
|
|
||||||
// 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
|
|
||||||
// deletion time, so we can check the deletion status in the query itself. There are no
|
|
||||||
// pending deletes for hosts, so we can call queryUndeleted. In this case, the initial string
|
|
||||||
// must be present, to avoid querying every host in the system. This restriction is enforced
|
|
||||||
// by queryUndeleted().
|
|
||||||
} else {
|
|
||||||
// Only return the first 1000 nameservers. This could result in an incomplete result set if
|
|
||||||
// a search asks for something like "ns*", but we need to enforce a limit in order to avoid
|
|
||||||
// arbitrarily long-running queries.
|
|
||||||
return queryItems(
|
|
||||||
HostResource.class,
|
|
||||||
"fullyQualifiedHostName",
|
|
||||||
partialStringQuery,
|
|
||||||
false, /* includeDeleted */
|
|
||||||
MAX_NAMESERVERS_IN_FIRST_STAGE)
|
|
||||||
.keys();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -329,18 +382,24 @@ public class RdapDomainSearchAction extends RdapActionBase {
|
||||||
* IP. To avoid this, fetch only the first 1000 nameservers. In all normal circumstances, this
|
* IP. To avoid this, fetch only the first 1000 nameservers. In all normal circumstances, this
|
||||||
* should be orders of magnitude more than there actually are. But it could result in us missing
|
* should be orders of magnitude more than there actually are. But it could result in us missing
|
||||||
* some domains.
|
* some domains.
|
||||||
|
*
|
||||||
|
* <p>The includeDeleted parameter does NOT cause deleted nameservers to be searched, only deleted
|
||||||
|
* domains which used to be connected to an undeleted nameserver.
|
||||||
*/
|
*/
|
||||||
private RdapSearchResults searchByNameserverIp(
|
private RdapSearchResults searchByNameserverIp(
|
||||||
final InetAddress inetAddress, final DateTime now) {
|
final InetAddress inetAddress, final DateTime now) {
|
||||||
return searchByNameserverRefs(
|
Query<HostResource> query =
|
||||||
ofy()
|
queryItems(
|
||||||
.load()
|
HostResource.class,
|
||||||
.type(HostResource.class)
|
"inetAddresses",
|
||||||
.filter("inetAddresses", inetAddress.getHostAddress())
|
inetAddress.getHostAddress(),
|
||||||
.filter("deletionTime", END_OF_TIME)
|
false,
|
||||||
.limit(MAX_NAMESERVERS_IN_FIRST_STAGE)
|
MAX_NAMESERVERS_IN_FIRST_STAGE);
|
||||||
.keys(),
|
Optional<String> desiredRegistrar = getDesiredRegistrar();
|
||||||
now);
|
if (desiredRegistrar.isPresent()) {
|
||||||
|
query = query.filter("currentSponsorClientId", desiredRegistrar.get());
|
||||||
|
}
|
||||||
|
return searchByNameserverRefs(query.keys(), now);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -360,12 +419,14 @@ public class RdapDomainSearchAction extends RdapActionBase {
|
||||||
int numHostKeysSearched = 0;
|
int numHostKeysSearched = 0;
|
||||||
for (List<Key<HostResource>> chunk : Iterables.partition(hostKeys, 30)) {
|
for (List<Key<HostResource>> chunk : Iterables.partition(hostKeys, 30)) {
|
||||||
numHostKeysSearched += chunk.size();
|
numHostKeysSearched += chunk.size();
|
||||||
for (DomainResource domain : ofy().load()
|
Query<DomainResource> query = ofy().load()
|
||||||
.type(DomainResource.class)
|
.type(DomainResource.class)
|
||||||
.filter("nsHosts in", chunk)
|
.filter("nsHosts in", chunk);
|
||||||
.filter("deletionTime >", now)
|
if (!shouldIncludeDeleted()) {
|
||||||
.limit(rdapResultSetMaxSize + 1)) {
|
query = query.filter("deletionTime >", now);
|
||||||
if (!domains.contains(domain)) {
|
}
|
||||||
|
for (DomainResource domain : query.limit(rdapResultSetMaxSize + 1)) {
|
||||||
|
if (!domains.contains(domain) && isAuthorized(domain, now)) {
|
||||||
if (domains.size() >= rdapResultSetMaxSize) {
|
if (domains.size() >= rdapResultSetMaxSize) {
|
||||||
return makeSearchResults(
|
return makeSearchResults(
|
||||||
ImmutableList.copyOf(domains), IncompletenessWarningType.TRUNCATED, now);
|
ImmutableList.copyOf(domains), IncompletenessWarningType.TRUNCATED, now);
|
||||||
|
@ -387,6 +448,17 @@ public class RdapDomainSearchAction extends RdapActionBase {
|
||||||
return makeSearchResults(domains, IncompletenessWarningType.NONE, now);
|
return makeSearchResults(domains, IncompletenessWarningType.NONE, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Output JSON from data in an {@link RdapResourcesAndIncompletenessWarningType} object. */
|
||||||
|
private RdapSearchResults makeSearchResults(
|
||||||
|
RdapResourcesAndIncompletenessWarningType<DomainResource>
|
||||||
|
resourcesAndIncompletenessWarningType,
|
||||||
|
DateTime now) {
|
||||||
|
return makeSearchResults(
|
||||||
|
resourcesAndIncompletenessWarningType.resources(),
|
||||||
|
resourcesAndIncompletenessWarningType.incompletenessWarningType(),
|
||||||
|
now);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Output JSON for a list of domains.
|
* Output JSON for a list of domains.
|
||||||
*
|
*
|
||||||
|
@ -401,12 +473,19 @@ public class RdapDomainSearchAction extends RdapActionBase {
|
||||||
OutputDataType outputDataType =
|
OutputDataType outputDataType =
|
||||||
(domains.size() > 1) ? OutputDataType.SUMMARY : OutputDataType.FULL;
|
(domains.size() > 1) ? OutputDataType.SUMMARY : OutputDataType.FULL;
|
||||||
RdapAuthorization authorization = getAuthorization();
|
RdapAuthorization authorization = getAuthorization();
|
||||||
ImmutableList.Builder<ImmutableMap<String, Object>> jsonBuilder = new ImmutableList.Builder<>();
|
List<ImmutableMap<String, Object>> jsonList = new ArrayList<>();
|
||||||
for (DomainResource domain : domains) {
|
for (DomainResource domain : domains) {
|
||||||
jsonBuilder.add(
|
jsonList.add(
|
||||||
rdapJsonFormatter.makeRdapJsonForDomain(
|
rdapJsonFormatter.makeRdapJsonForDomain(
|
||||||
domain, false, rdapLinkBase, rdapWhoisServer, now, outputDataType, authorization));
|
domain, false, rdapLinkBase, rdapWhoisServer, now, outputDataType, authorization));
|
||||||
|
if (jsonList.size() >= rdapResultSetMaxSize) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return RdapSearchResults.create(jsonBuilder.build(), incompletenessWarningType);
|
return RdapSearchResults.create(
|
||||||
|
ImmutableList.copyOf(jsonList),
|
||||||
|
(jsonList.size() < domains.size())
|
||||||
|
? IncompletenessWarningType.TRUNCATED
|
||||||
|
: incompletenessWarningType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,7 +175,8 @@ public class RdapEntitySearchAction extends RdapActionBase {
|
||||||
shouldIncludeDeleted()
|
shouldIncludeDeleted()
|
||||||
? (RESULT_SET_SIZE_SCALING_FACTOR * (rdapResultSetMaxSize + 1))
|
? (RESULT_SET_SIZE_SCALING_FACTOR * (rdapResultSetMaxSize + 1))
|
||||||
: (rdapResultSetMaxSize + 1));
|
: (rdapResultSetMaxSize + 1));
|
||||||
return makeSearchResults(getMatchingResources(query, now), registrars, now);
|
return makeSearchResults(
|
||||||
|
getMatchingResources(query, shouldIncludeDeleted(), now), registrars, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -226,7 +227,8 @@ public class RdapEntitySearchAction extends RdapActionBase {
|
||||||
shouldIncludeDeleted()
|
shouldIncludeDeleted()
|
||||||
? (RESULT_SET_SIZE_SCALING_FACTOR * (rdapResultSetMaxSize + 1))
|
? (RESULT_SET_SIZE_SCALING_FACTOR * (rdapResultSetMaxSize + 1))
|
||||||
: (rdapResultSetMaxSize + 1));
|
: (rdapResultSetMaxSize + 1));
|
||||||
return makeSearchResults(getMatchingResources(query, now), registrars, now);
|
return makeSearchResults(
|
||||||
|
getMatchingResources(query, shouldIncludeDeleted(), now), registrars, now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -219,7 +219,7 @@ public class RdapNameserverSearchAction extends RdapActionBase {
|
||||||
shouldIncludeDeleted()
|
shouldIncludeDeleted()
|
||||||
? (RESULT_SET_SIZE_SCALING_FACTOR * (rdapResultSetMaxSize + 1))
|
? (RESULT_SET_SIZE_SCALING_FACTOR * (rdapResultSetMaxSize + 1))
|
||||||
: (rdapResultSetMaxSize + 1));
|
: (rdapResultSetMaxSize + 1));
|
||||||
return makeSearchResults(getMatchingResources(query, now), now);
|
return makeSearchResults(getMatchingResources(query, shouldIncludeDeleted(), now), now);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Searches for nameservers by IP address, returning a JSON array of nameserver info maps. */
|
/** Searches for nameservers by IP address, returning a JSON array of nameserver info maps. */
|
||||||
|
@ -234,7 +234,7 @@ public class RdapNameserverSearchAction extends RdapActionBase {
|
||||||
shouldIncludeDeleted()
|
shouldIncludeDeleted()
|
||||||
? (RESULT_SET_SIZE_SCALING_FACTOR * (rdapResultSetMaxSize + 1))
|
? (RESULT_SET_SIZE_SCALING_FACTOR * (rdapResultSetMaxSize + 1))
|
||||||
: (rdapResultSetMaxSize + 1));
|
: (rdapResultSetMaxSize + 1));
|
||||||
return makeSearchResults(getMatchingResources(query, now), now);
|
return makeSearchResults(getMatchingResources(query, shouldIncludeDeleted(), now), now);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -50,6 +50,7 @@ import google.registry.testing.InjectRule;
|
||||||
import google.registry.ui.server.registrar.SessionUtils;
|
import google.registry.ui.server.registrar.SessionUtils;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
|
@ -80,6 +81,7 @@ public class RdapDomainActionTest {
|
||||||
private final SessionUtils sessionUtils = mock(SessionUtils.class);
|
private final SessionUtils sessionUtils = mock(SessionUtils.class);
|
||||||
private final User user = new User("rdap.user@example.com", "gmail.com", "12345");
|
private final User user = new User("rdap.user@example.com", "gmail.com", "12345");
|
||||||
private final UserAuthInfo userAuthInfo = UserAuthInfo.create(user, false);
|
private final UserAuthInfo userAuthInfo = UserAuthInfo.create(user, false);
|
||||||
|
private final UserAuthInfo adminUserAuthInfo = UserAuthInfo.create(user, true);
|
||||||
|
|
||||||
private RdapDomainAction action;
|
private RdapDomainAction action;
|
||||||
|
|
||||||
|
@ -121,12 +123,29 @@ public class RdapDomainActionTest {
|
||||||
registrantLol, adminContactLol, techContactLol, host1, host2, registrarLol));
|
registrantLol, adminContactLol, techContactLol, host1, host2, registrarLol));
|
||||||
|
|
||||||
// deleted domain in lol
|
// deleted domain in lol
|
||||||
|
HostResource hostDodo2 = makeAndPersistHostResource(
|
||||||
|
"ns2.dodo.lol", "bad:f00d:cafe:0:0:0:15:beef", clock.nowUtc().minusYears(2));
|
||||||
DomainBase domainDeleted = persistResource(makeDomainResource("dodo.lol",
|
DomainBase domainDeleted = persistResource(makeDomainResource("dodo.lol",
|
||||||
registrantLol,
|
makeAndPersistContactResource(
|
||||||
adminContactLol,
|
"5372808-ERL",
|
||||||
techContactLol,
|
"Goblin Market",
|
||||||
|
"lol@cat.lol",
|
||||||
|
clock.nowUtc().minusYears(1),
|
||||||
|
registrarLol),
|
||||||
|
makeAndPersistContactResource(
|
||||||
|
"5372808-IRL",
|
||||||
|
"Santa Claus",
|
||||||
|
"BOFH@cat.lol",
|
||||||
|
clock.nowUtc().minusYears(2),
|
||||||
|
registrarLol),
|
||||||
|
makeAndPersistContactResource(
|
||||||
|
"5372808-TRL",
|
||||||
|
"The Raven",
|
||||||
|
"bog@cat.lol",
|
||||||
|
clock.nowUtc().minusYears(3),
|
||||||
|
registrarLol),
|
||||||
host1,
|
host1,
|
||||||
host2,
|
hostDodo2,
|
||||||
registrarLol).asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
|
registrarLol).asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
|
||||||
|
|
||||||
// xn--q9jyb4c
|
// xn--q9jyb4c
|
||||||
|
@ -211,7 +230,7 @@ public class RdapDomainActionTest {
|
||||||
HistoryEntry.Type.DOMAIN_CREATE,
|
HistoryEntry.Type.DOMAIN_CREATE,
|
||||||
Period.create(1, Period.Unit.YEARS),
|
Period.create(1, Period.Unit.YEARS),
|
||||||
"created",
|
"created",
|
||||||
clock.nowUtc()));
|
clock.nowUtc().minusYears(1)));
|
||||||
persistResource(
|
persistResource(
|
||||||
makeHistoryEntry(
|
makeHistoryEntry(
|
||||||
domainCatIdn,
|
domainCatIdn,
|
||||||
|
@ -226,18 +245,36 @@ public class RdapDomainActionTest {
|
||||||
Period.create(1, Period.Unit.YEARS),
|
Period.create(1, Period.Unit.YEARS),
|
||||||
"created",
|
"created",
|
||||||
clock.nowUtc()));
|
clock.nowUtc()));
|
||||||
|
persistResource(
|
||||||
|
makeHistoryEntry(
|
||||||
|
domainDeleted,
|
||||||
|
HistoryEntry.Type.DOMAIN_DELETE,
|
||||||
|
Period.create(1, Period.Unit.YEARS),
|
||||||
|
"deleted",
|
||||||
|
clock.nowUtc().minusMonths(6)));
|
||||||
|
|
||||||
action = new RdapDomainAction();
|
action = new RdapDomainAction();
|
||||||
action.clock = clock;
|
action.clock = clock;
|
||||||
action.request = request;
|
action.request = request;
|
||||||
action.response = response;
|
action.response = response;
|
||||||
|
action.registrarParam = Optional.empty();
|
||||||
|
action.includeDeletedParam = Optional.empty();
|
||||||
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
||||||
action.rdapLinkBase = "https://example.com/rdap/";
|
action.rdapLinkBase = "https://example.com/rdap/";
|
||||||
action.rdapWhoisServer = null;
|
action.rdapWhoisServer = null;
|
||||||
action.sessionUtils = sessionUtils;
|
action.sessionUtils = sessionUtils;
|
||||||
action.authResult = AuthResult.create(AuthLevel.USER, userAuthInfo);
|
action.authResult = AuthResult.create(AuthLevel.USER, userAuthInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void login(String clientId) {
|
||||||
when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(true);
|
when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(true);
|
||||||
when(sessionUtils.getRegistrarClientId(request)).thenReturn("evilregistrar");
|
when(sessionUtils.getRegistrarClientId(request)).thenReturn(clientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loginAsAdmin() {
|
||||||
|
when(sessionUtils.checkRegistrarConsoleLogin(request, adminUserAuthInfo)).thenReturn(true);
|
||||||
|
when(sessionUtils.getRegistrarClientId(request)).thenReturn("irrelevant");
|
||||||
|
action.authResult = AuthResult.create(AuthLevel.USER, adminUserAuthInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object generateActualJson(String domainName) {
|
private Object generateActualJson(String domainName) {
|
||||||
|
@ -251,7 +288,7 @@ public class RdapDomainActionTest {
|
||||||
String punycodeName,
|
String punycodeName,
|
||||||
String handle,
|
String handle,
|
||||||
String expectedOutputFile) {
|
String expectedOutputFile) {
|
||||||
return generateExpectedJson(name, punycodeName, handle, null, expectedOutputFile);
|
return generateExpectedJson(name, punycodeName, handle, null, null, null, expectedOutputFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object generateExpectedJson(
|
private Object generateExpectedJson(
|
||||||
|
@ -259,25 +296,40 @@ public class RdapDomainActionTest {
|
||||||
String punycodeName,
|
String punycodeName,
|
||||||
String handle,
|
String handle,
|
||||||
@Nullable List<String> contactRoids,
|
@Nullable List<String> contactRoids,
|
||||||
|
@Nullable List<String> nameserverRoids,
|
||||||
|
@Nullable List<String> nameserverNames,
|
||||||
String expectedOutputFile) {
|
String expectedOutputFile) {
|
||||||
ImmutableMap.Builder<String, String> substitutionsBuilder = new ImmutableMap.Builder<>();
|
ImmutableMap.Builder<String, String> substitutionsBuilder = new ImmutableMap.Builder<>();
|
||||||
substitutionsBuilder.put("NAME", name);
|
substitutionsBuilder.put("NAME", name);
|
||||||
substitutionsBuilder.put("PUNYCODENAME", (punycodeName == null) ? name : punycodeName);
|
substitutionsBuilder.put("PUNYCODENAME", (punycodeName == null) ? name : punycodeName);
|
||||||
substitutionsBuilder.put("HANDLE", handle);
|
substitutionsBuilder.put("HANDLE", handle);
|
||||||
substitutionsBuilder.put("TYPE", "domain name");
|
substitutionsBuilder.put("TYPE", "domain name");
|
||||||
substitutionsBuilder.put("NAMESERVER1ROID", "8-ROID");
|
|
||||||
substitutionsBuilder.put("NAMESERVER1NAME", "ns1.cat.lol");
|
|
||||||
substitutionsBuilder.put("NAMESERVER1PUNYCODENAME", "ns1.cat.lol");
|
|
||||||
substitutionsBuilder.put("NAMESERVER1ADDRESS", "1.2.3.4");
|
substitutionsBuilder.put("NAMESERVER1ADDRESS", "1.2.3.4");
|
||||||
substitutionsBuilder.put("NAMESERVER2ROID", "A-ROID");
|
|
||||||
substitutionsBuilder.put("NAMESERVER2NAME", "ns2.cat.lol");
|
|
||||||
substitutionsBuilder.put("NAMESERVER2PUNYCODENAME", "ns2.cat.lol");
|
|
||||||
substitutionsBuilder.put("NAMESERVER2ADDRESS", "bad:f00d:cafe::15:beef");
|
substitutionsBuilder.put("NAMESERVER2ADDRESS", "bad:f00d:cafe::15:beef");
|
||||||
if (contactRoids != null) {
|
if (contactRoids != null) {
|
||||||
for (int i = 0; i < contactRoids.size(); i++) {
|
for (int i = 0; i < contactRoids.size(); i++) {
|
||||||
substitutionsBuilder.put("CONTACT" + (i + 1) + "ROID", contactRoids.get(i));
|
substitutionsBuilder.put("CONTACT" + (i + 1) + "ROID", contactRoids.get(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (nameserverRoids != null) {
|
||||||
|
for (int i = 0; i < nameserverRoids.size(); i++) {
|
||||||
|
substitutionsBuilder.put("NAMESERVER" + (i + 1) + "ROID", nameserverRoids.get(i));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
substitutionsBuilder.put("NAMESERVER1ROID", "8-ROID");
|
||||||
|
substitutionsBuilder.put("NAMESERVER2ROID", "A-ROID");
|
||||||
|
}
|
||||||
|
if (nameserverNames != null) {
|
||||||
|
for (int i = 0; i < nameserverRoids.size(); i++) {
|
||||||
|
substitutionsBuilder.put("NAMESERVER" + (i + 1) + "NAME", nameserverNames.get(i));
|
||||||
|
substitutionsBuilder.put("NAMESERVER" + (i + 1) + "PUNYCODENAME", nameserverNames.get(i));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
substitutionsBuilder.put("NAMESERVER1NAME", "ns1.cat.lol");
|
||||||
|
substitutionsBuilder.put("NAMESERVER1PUNYCODENAME", "ns1.cat.lol");
|
||||||
|
substitutionsBuilder.put("NAMESERVER2NAME", "ns2.cat.lol");
|
||||||
|
substitutionsBuilder.put("NAMESERVER2PUNYCODENAME", "ns2.cat.lol");
|
||||||
|
}
|
||||||
return JSONValue.parse(
|
return JSONValue.parse(
|
||||||
loadFileWithSubstitutions(
|
loadFileWithSubstitutions(
|
||||||
this.getClass(), expectedOutputFile, substitutionsBuilder.build()));
|
this.getClass(), expectedOutputFile, substitutionsBuilder.build()));
|
||||||
|
@ -288,9 +340,28 @@ public class RdapDomainActionTest {
|
||||||
String punycodeName,
|
String punycodeName,
|
||||||
String handle,
|
String handle,
|
||||||
@Nullable List<String> contactRoids,
|
@Nullable List<String> contactRoids,
|
||||||
|
@Nullable List<String> nameserverRoids,
|
||||||
String expectedOutputFile) {
|
String expectedOutputFile) {
|
||||||
Object obj = generateExpectedJson(
|
return generateExpectedJsonWithTopLevelEntries(
|
||||||
name, punycodeName, handle, contactRoids, expectedOutputFile);
|
name, punycodeName, handle, contactRoids, nameserverRoids, null, expectedOutputFile);
|
||||||
|
}
|
||||||
|
private Object generateExpectedJsonWithTopLevelEntries(
|
||||||
|
String name,
|
||||||
|
String punycodeName,
|
||||||
|
String handle,
|
||||||
|
@Nullable List<String> contactRoids,
|
||||||
|
@Nullable List<String> nameserverRoids,
|
||||||
|
@Nullable List<String> nameserverNames,
|
||||||
|
String expectedOutputFile) {
|
||||||
|
Object obj =
|
||||||
|
generateExpectedJson(
|
||||||
|
name,
|
||||||
|
punycodeName,
|
||||||
|
handle,
|
||||||
|
contactRoids,
|
||||||
|
nameserverRoids,
|
||||||
|
nameserverNames,
|
||||||
|
expectedOutputFile);
|
||||||
if (obj instanceof Map) {
|
if (obj instanceof Map) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Map<String, Object> map = (Map<String, Object>) obj;
|
Map<String, Object> map = (Map<String, Object>) obj;
|
||||||
|
@ -331,6 +402,7 @@ public class RdapDomainActionTest {
|
||||||
expectedOutputFile.equals("rdap_domain.json")
|
expectedOutputFile.equals("rdap_domain.json")
|
||||||
? ImmutableList.of("4-ROID", "6-ROID", "2-ROID")
|
? ImmutableList.of("4-ROID", "6-ROID", "2-ROID")
|
||||||
: null,
|
: null,
|
||||||
|
ImmutableList.of("8-ROID", "A-ROID"),
|
||||||
expectedOutputFile));
|
expectedOutputFile));
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
@ -361,107 +433,114 @@ public class RdapDomainActionTest {
|
||||||
assertThat(response.getStatus()).isEqualTo(400);
|
assertThat(response.getStatus()).isEqualTo(400);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDeletedDomain_returns404() throws Exception {
|
|
||||||
assertJsonEqual(
|
|
||||||
generateActualJson("dodo.lol"),
|
|
||||||
generateExpectedJson("dodo.lol not found", null, "1", "rdap_error_404.json"));
|
|
||||||
assertThat(response.getStatus()).isEqualTo(404);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidDomain_works() throws Exception {
|
public void testValidDomain_works() throws Exception {
|
||||||
|
login("evilregistrar");
|
||||||
assertProperResponseForCatLol("cat.lol", "rdap_domain.json");
|
assertProperResponseForCatLol("cat.lol", "rdap_domain.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidDomain_works_sameRegistrarRequested() throws Exception {
|
||||||
|
action.registrarParam = Optional.of("evilregistrar");
|
||||||
|
login("evilregistrar");
|
||||||
|
assertProperResponseForCatLol("cat.lol", "rdap_domain.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidDomain_notFound_differentRegistrarRequested() throws Exception {
|
||||||
|
action.registrarParam = Optional.of("idnregistrar");
|
||||||
|
generateActualJson("cat.lol");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidDomain_asAdministrator_works() throws Exception {
|
public void testValidDomain_asAdministrator_works() throws Exception {
|
||||||
UserAuthInfo adminUserAuthInfo = UserAuthInfo.create(user, true);
|
loginAsAdmin();
|
||||||
action.authResult = AuthResult.create(AuthLevel.USER, adminUserAuthInfo);
|
|
||||||
when(sessionUtils.checkRegistrarConsoleLogin(request, adminUserAuthInfo)).thenReturn(false);
|
|
||||||
when(sessionUtils.getRegistrarClientId(request)).thenReturn("noregistrar");
|
|
||||||
assertProperResponseForCatLol("cat.lol", "rdap_domain.json");
|
assertProperResponseForCatLol("cat.lol", "rdap_domain.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidDomain_notLoggedIn_noContacts() throws Exception {
|
public void testValidDomain_notLoggedIn_noContacts() throws Exception {
|
||||||
when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(false);
|
|
||||||
assertProperResponseForCatLol("cat.lol", "rdap_domain_no_contacts.json");
|
assertProperResponseForCatLol("cat.lol", "rdap_domain_no_contacts.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidDomain_loggedInAsOtherRegistrar_noContacts() throws Exception {
|
public void testValidDomain_loggedInAsOtherRegistrar_noContacts() throws Exception {
|
||||||
when(sessionUtils.getRegistrarClientId(request)).thenReturn("otherregistrar");
|
login("idnregistrar");
|
||||||
assertProperResponseForCatLol("cat.lol", "rdap_domain_no_contacts.json");
|
assertProperResponseForCatLol("cat.lol", "rdap_domain_no_contacts.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpperCase_ignored() throws Exception {
|
public void testUpperCase_ignored() throws Exception {
|
||||||
assertProperResponseForCatLol("CaT.lOl", "rdap_domain.json");
|
assertProperResponseForCatLol("CaT.lOl", "rdap_domain_no_contacts.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTrailingDot_ignored() throws Exception {
|
public void testTrailingDot_ignored() throws Exception {
|
||||||
assertProperResponseForCatLol("cat.lol.", "rdap_domain.json");
|
assertProperResponseForCatLol("cat.lol.", "rdap_domain_no_contacts.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testQueryParameter_ignored() throws Exception {
|
public void testQueryParameter_ignored() throws Exception {
|
||||||
assertProperResponseForCatLol("cat.lol?key=value", "rdap_domain.json");
|
assertProperResponseForCatLol("cat.lol?key=value", "rdap_domain_no_contacts.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIdnDomain_works() throws Exception {
|
public void testIdnDomain_works() throws Exception {
|
||||||
when(sessionUtils.getRegistrarClientId(request)).thenReturn("idnregistrar");
|
login("idnregistrar");
|
||||||
assertJsonEqual(
|
assertJsonEqual(
|
||||||
generateActualJson("cat.みんな"),
|
generateActualJson("cat.みんな"),
|
||||||
generateExpectedJsonWithTopLevelEntries(
|
generateExpectedJsonWithTopLevelEntries(
|
||||||
"cat.みんな",
|
"cat.みんな",
|
||||||
"cat.xn--q9jyb4c",
|
"cat.xn--q9jyb4c",
|
||||||
"15-Q9JYB4C",
|
"1D-Q9JYB4C",
|
||||||
ImmutableList.of("11-ROID", "13-ROID", "F-ROID"),
|
ImmutableList.of("19-ROID", "1B-ROID", "17-ROID"),
|
||||||
|
ImmutableList.of("8-ROID", "A-ROID"),
|
||||||
"rdap_domain_unicode.json"));
|
"rdap_domain_unicode.json"));
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIdnDomainWithPercentEncoding_works() throws Exception {
|
public void testIdnDomainWithPercentEncoding_works() throws Exception {
|
||||||
when(sessionUtils.getRegistrarClientId(request)).thenReturn("idnregistrar");
|
login("idnregistrar");
|
||||||
assertJsonEqual(
|
assertJsonEqual(
|
||||||
generateActualJson("cat.%E3%81%BF%E3%82%93%E3%81%AA"),
|
generateActualJson("cat.%E3%81%BF%E3%82%93%E3%81%AA"),
|
||||||
generateExpectedJsonWithTopLevelEntries(
|
generateExpectedJsonWithTopLevelEntries(
|
||||||
"cat.みんな",
|
"cat.みんな",
|
||||||
"cat.xn--q9jyb4c",
|
"cat.xn--q9jyb4c",
|
||||||
"15-Q9JYB4C",
|
"1D-Q9JYB4C",
|
||||||
ImmutableList.of("11-ROID", "13-ROID", "F-ROID"),
|
ImmutableList.of("19-ROID", "1B-ROID", "17-ROID"),
|
||||||
|
ImmutableList.of("8-ROID", "A-ROID"),
|
||||||
"rdap_domain_unicode.json"));
|
"rdap_domain_unicode.json"));
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPunycodeDomain_works() throws Exception {
|
public void testPunycodeDomain_works() throws Exception {
|
||||||
when(sessionUtils.getRegistrarClientId(request)).thenReturn("idnregistrar");
|
login("idnregistrar");
|
||||||
assertJsonEqual(
|
assertJsonEqual(
|
||||||
generateActualJson("cat.xn--q9jyb4c"),
|
generateActualJson("cat.xn--q9jyb4c"),
|
||||||
generateExpectedJsonWithTopLevelEntries(
|
generateExpectedJsonWithTopLevelEntries(
|
||||||
"cat.みんな",
|
"cat.みんな",
|
||||||
"cat.xn--q9jyb4c",
|
"cat.xn--q9jyb4c",
|
||||||
"15-Q9JYB4C",
|
"1D-Q9JYB4C",
|
||||||
ImmutableList.of("11-ROID", "13-ROID", "F-ROID"),
|
ImmutableList.of("19-ROID", "1B-ROID", "17-ROID"),
|
||||||
|
ImmutableList.of("8-ROID", "A-ROID"),
|
||||||
"rdap_domain_unicode.json"));
|
"rdap_domain_unicode.json"));
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMultilevelDomain_works() throws Exception {
|
public void testMultilevelDomain_works() throws Exception {
|
||||||
when(sessionUtils.getRegistrarClientId(request)).thenReturn("1tldregistrar");
|
login("1tldregistrar");
|
||||||
assertJsonEqual(
|
assertJsonEqual(
|
||||||
generateActualJson("cat.1.tld"),
|
generateActualJson("cat.1.tld"),
|
||||||
generateExpectedJsonWithTopLevelEntries(
|
generateExpectedJsonWithTopLevelEntries(
|
||||||
"cat.1.tld",
|
"cat.1.tld",
|
||||||
null,
|
null,
|
||||||
"1D-1_TLD",
|
"25-1_TLD",
|
||||||
ImmutableList.of("19-ROID", "1B-ROID", "17-ROID"),
|
ImmutableList.of("21-ROID", "23-ROID", "1F-ROID"),
|
||||||
|
ImmutableList.of("8-ROID", "A-ROID"),
|
||||||
"rdap_domain.json"));
|
"rdap_domain.json"));
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
@ -474,4 +553,68 @@ public class RdapDomainActionTest {
|
||||||
generateActualJson("cat.lol");
|
generateActualJson("cat.lol");
|
||||||
assertThat(response.getStatus()).isEqualTo(404);
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeletedDomain_notFound() throws Exception {
|
||||||
|
assertJsonEqual(
|
||||||
|
generateActualJson("dodo.lol"),
|
||||||
|
generateExpectedJson("dodo.lol not found", null, "1", "rdap_error_404.json"));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeletedDomain_notFound_includeDeletedSetFalse() throws Exception {
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
generateActualJson("dodo.lol");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeletedDomain_notFound_notLoggedIn() throws Exception {
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
generateActualJson("dodo.lol");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeletedDomain_notFound_loggedInAsDifferentRegistrar() throws Exception {
|
||||||
|
login("1tldregistrar");
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
generateActualJson("dodo.lol");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeletedDomain_works_loggedInAsCorrectRegistrar() throws Exception {
|
||||||
|
login("evilregistrar");
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
assertJsonEqual(
|
||||||
|
generateActualJson("dodo.lol"),
|
||||||
|
generateExpectedJsonWithTopLevelEntries(
|
||||||
|
"dodo.lol",
|
||||||
|
null,
|
||||||
|
"15-LOL",
|
||||||
|
ImmutableList.of("11-ROID", "13-ROID", "F-ROID"),
|
||||||
|
ImmutableList.of("8-ROID", "D-ROID"),
|
||||||
|
ImmutableList.of("ns1.cat.lol", "ns2.dodo.lol"),
|
||||||
|
"rdap_domain_deleted.json"));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeletedDomain_works_loggedInAsAdmin() throws Exception {
|
||||||
|
loginAsAdmin();
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
assertJsonEqual(
|
||||||
|
generateActualJson("dodo.lol"),
|
||||||
|
generateExpectedJsonWithTopLevelEntries(
|
||||||
|
"dodo.lol",
|
||||||
|
null,
|
||||||
|
"15-LOL",
|
||||||
|
ImmutableList.of("11-ROID", "13-ROID", "F-ROID"),
|
||||||
|
ImmutableList.of("8-ROID", "D-ROID"),
|
||||||
|
ImmutableList.of("ns1.cat.lol", "ns2.dodo.lol"),
|
||||||
|
"rdap_domain_deleted.json"));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,8 @@ public class RdapDomainSearchActionTest {
|
||||||
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01T00:00:00Z"));
|
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01T00:00:00Z"));
|
||||||
private final SessionUtils sessionUtils = mock(SessionUtils.class);
|
private final SessionUtils sessionUtils = mock(SessionUtils.class);
|
||||||
private final User user = new User("rdap.user@example.com", "gmail.com", "12345");
|
private final User user = new User("rdap.user@example.com", "gmail.com", "12345");
|
||||||
UserAuthInfo userAuthInfo = UserAuthInfo.create(user, false);
|
private final UserAuthInfo userAuthInfo = UserAuthInfo.create(user, false);
|
||||||
|
private final UserAuthInfo adminUserAuthInfo = UserAuthInfo.create(user, true);
|
||||||
|
|
||||||
private final RdapDomainSearchAction action = new RdapDomainSearchAction();
|
private final RdapDomainSearchAction action = new RdapDomainSearchAction();
|
||||||
|
|
||||||
|
@ -104,6 +105,7 @@ public class RdapDomainSearchActionTest {
|
||||||
private ContactResource contact3;
|
private ContactResource contact3;
|
||||||
private HostResource hostNs1CatLol;
|
private HostResource hostNs1CatLol;
|
||||||
private HostResource hostNs2CatLol;
|
private HostResource hostNs2CatLol;
|
||||||
|
private HistoryEntry historyEntryCatLolCreate;
|
||||||
private Map<String, HostResource> hostNameToHostMap = new HashMap<>();
|
private Map<String, HostResource> hostNameToHostMap = new HashMap<>();
|
||||||
|
|
||||||
enum RequestType { NONE, NAME, NS_LDH_NAME, NS_IP }
|
enum RequestType { NONE, NAME, NS_LDH_NAME, NS_IP }
|
||||||
|
@ -246,7 +248,7 @@ public class RdapDomainSearchActionTest {
|
||||||
registrar),
|
registrar),
|
||||||
hostNs1CatLol,
|
hostNs1CatLol,
|
||||||
addHostToMap(makeAndPersistHostResource(
|
addHostToMap(makeAndPersistHostResource(
|
||||||
"ns2.external.tld", "bad:f00d:cafe:0:0:0:15:beef", clock.nowUtc().minusYears(2))),
|
"ns2.external.tld", "bad:f00d:cafe:0:0:0:16:beef", clock.nowUtc().minusYears(2))),
|
||||||
registrar)
|
registrar)
|
||||||
.asBuilder()
|
.asBuilder()
|
||||||
.setCreationTimeForTest(clock.nowUtc().minusYears(3))
|
.setCreationTimeForTest(clock.nowUtc().minusYears(3))
|
||||||
|
@ -287,7 +289,7 @@ public class RdapDomainSearchActionTest {
|
||||||
// cat.1.test
|
// cat.1.test
|
||||||
createTld("1.test");
|
createTld("1.test");
|
||||||
registrar =
|
registrar =
|
||||||
persistResource(makeRegistrar("unicoderegistrar", "1.test", Registrar.State.ACTIVE));
|
persistResource(makeRegistrar("multiregistrar", "1.test", Registrar.State.ACTIVE));
|
||||||
persistSimpleResources(makeRegistrarContacts(registrar));
|
persistSimpleResources(makeRegistrarContacts(registrar));
|
||||||
domainMultipart = persistResource(makeDomainResource(
|
domainMultipart = persistResource(makeDomainResource(
|
||||||
"cat.1.test",
|
"cat.1.test",
|
||||||
|
@ -319,8 +321,10 @@ public class RdapDomainSearchActionTest {
|
||||||
.setCreationTimeForTest(clock.nowUtc().minusYears(3))
|
.setCreationTimeForTest(clock.nowUtc().minusYears(3))
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
|
persistResource(makeRegistrar("otherregistrar", "other", Registrar.State.ACTIVE));
|
||||||
|
|
||||||
// history entries
|
// history entries
|
||||||
persistResource(
|
historyEntryCatLolCreate = persistResource(
|
||||||
makeHistoryEntry(
|
makeHistoryEntry(
|
||||||
domainCatLol,
|
domainCatLol,
|
||||||
HistoryEntry.Type.DOMAIN_CREATE,
|
HistoryEntry.Type.DOMAIN_CREATE,
|
||||||
|
@ -366,8 +370,17 @@ public class RdapDomainSearchActionTest {
|
||||||
action.rdapWhoisServer = null;
|
action.rdapWhoisServer = null;
|
||||||
action.sessionUtils = sessionUtils;
|
action.sessionUtils = sessionUtils;
|
||||||
action.authResult = AuthResult.create(AuthLevel.USER, userAuthInfo);
|
action.authResult = AuthResult.create(AuthLevel.USER, userAuthInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void login(String clientId) {
|
||||||
when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(true);
|
when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(true);
|
||||||
when(sessionUtils.getRegistrarClientId(request)).thenReturn("evilregistrar");
|
when(sessionUtils.getRegistrarClientId(request)).thenReturn(clientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loginAsAdmin() {
|
||||||
|
when(sessionUtils.checkRegistrarConsoleLogin(request, adminUserAuthInfo)).thenReturn(true);
|
||||||
|
when(sessionUtils.getRegistrarClientId(request)).thenReturn("irrelevant");
|
||||||
|
action.authResult = AuthResult.create(AuthLevel.USER, adminUserAuthInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object generateExpectedJsonForTwoDomains() {
|
private Object generateExpectedJsonForTwoDomains() {
|
||||||
|
@ -477,6 +490,98 @@ public class RdapDomainSearchActionTest {
|
||||||
return new JSONObject(builder.build());
|
return new JSONObject(builder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void deleteCatLol() {
|
||||||
|
persistResource(
|
||||||
|
domainCatLol
|
||||||
|
.asBuilder()
|
||||||
|
.setCreationTimeForTest(clock.nowUtc().minusYears(1))
|
||||||
|
.setDeletionTime(clock.nowUtc().minusMonths(6))
|
||||||
|
.build());
|
||||||
|
persistResource(
|
||||||
|
historyEntryCatLolCreate
|
||||||
|
.asBuilder()
|
||||||
|
.setModificationTime(clock.nowUtc().minusYears(1))
|
||||||
|
.build());
|
||||||
|
persistResource(
|
||||||
|
makeHistoryEntry(
|
||||||
|
domainCatLol,
|
||||||
|
HistoryEntry.Type.DOMAIN_DELETE,
|
||||||
|
Period.create(1, Period.Unit.YEARS),
|
||||||
|
"deleted",
|
||||||
|
clock.nowUtc().minusMonths(6)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createManyDomainsAndHosts(
|
||||||
|
int numActiveDomains, int numTotalDomainsPerActiveDomain, int numHosts) {
|
||||||
|
ImmutableSet.Builder<Key<HostResource>> hostKeysBuilder = new ImmutableSet.Builder<>();
|
||||||
|
ImmutableSet.Builder<String> subordinateHostnamesBuilder = new ImmutableSet.Builder<>();
|
||||||
|
String mainDomainName = String.format("domain%d.lol", numTotalDomainsPerActiveDomain);
|
||||||
|
for (int i = 1; i <= numHosts; i++) {
|
||||||
|
String hostName = String.format("ns%d.%s", i, mainDomainName);
|
||||||
|
subordinateHostnamesBuilder.add(hostName);
|
||||||
|
HostResource host = makeAndPersistHostResource(
|
||||||
|
hostName, String.format("5.5.%d.%d", 5 + i / 250, i % 250), clock.nowUtc().minusYears(1));
|
||||||
|
hostKeysBuilder.add(Key.create(host));
|
||||||
|
}
|
||||||
|
ImmutableSet<Key<HostResource>> hostKeys = hostKeysBuilder.build();
|
||||||
|
// Create all the domains at once, then persist them in parallel, for increased efficiency.
|
||||||
|
ImmutableList.Builder<DomainResource> domainsBuilder = new ImmutableList.Builder<>();
|
||||||
|
for (int i = 1; i <= numActiveDomains * numTotalDomainsPerActiveDomain; i++) {
|
||||||
|
String domainName = String.format("domain%d.lol", i);
|
||||||
|
DomainResource.Builder builder =
|
||||||
|
makeDomainResource(
|
||||||
|
domainName, contact1, contact2, contact3, null, null, registrar)
|
||||||
|
.asBuilder()
|
||||||
|
.setNameservers(hostKeys)
|
||||||
|
.setCreationTimeForTest(clock.nowUtc().minusYears(3));
|
||||||
|
if (domainName.equals(mainDomainName)) {
|
||||||
|
builder.setSubordinateHosts(subordinateHostnamesBuilder.build());
|
||||||
|
}
|
||||||
|
if (i % numTotalDomainsPerActiveDomain != 0) {
|
||||||
|
builder = builder.setDeletionTime(clock.nowUtc().minusDays(1));
|
||||||
|
}
|
||||||
|
domainsBuilder.add(builder.build());
|
||||||
|
}
|
||||||
|
persistResources(domainsBuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object readMultiDomainFile(
|
||||||
|
String fileName,
|
||||||
|
String domainName1,
|
||||||
|
String domainHandle1,
|
||||||
|
String domainName2,
|
||||||
|
String domainHandle2,
|
||||||
|
String domainName3,
|
||||||
|
String domainHandle3,
|
||||||
|
String domainName4,
|
||||||
|
String domainHandle4) {
|
||||||
|
return JSONValue.parse(loadFileWithSubstitutions(
|
||||||
|
this.getClass(),
|
||||||
|
fileName,
|
||||||
|
new ImmutableMap.Builder<String, String>()
|
||||||
|
.put("DOMAINNAME1", domainName1)
|
||||||
|
.put("DOMAINHANDLE1", domainHandle1)
|
||||||
|
.put("DOMAINNAME2", domainName2)
|
||||||
|
.put("DOMAINHANDLE2", domainHandle2)
|
||||||
|
.put("DOMAINNAME3", domainName3)
|
||||||
|
.put("DOMAINHANDLE3", domainHandle3)
|
||||||
|
.put("DOMAINNAME4", domainName4)
|
||||||
|
.put("DOMAINHANDLE4", domainHandle4)
|
||||||
|
.build()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkNumberOfDomainsInResult(Object obj, int expected) {
|
||||||
|
assertThat(obj).isInstanceOf(Map.class);
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<String, Object> map = (Map<String, Object>) obj;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<Object> domains = (List<Object>) map.get("domainSearchResults");
|
||||||
|
|
||||||
|
assertThat(domains).hasSize(expected);
|
||||||
|
}
|
||||||
|
|
||||||
private void runSuccessfulTestWithCatLol(
|
private void runSuccessfulTestWithCatLol(
|
||||||
RequestType requestType, String queryString, String fileName) {
|
RequestType requestType, String queryString, String fileName) {
|
||||||
runSuccessfulTest(
|
runSuccessfulTest(
|
||||||
|
@ -582,26 +687,38 @@ public class RdapDomainSearchActionTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDomainMatch_found() throws Exception {
|
public void testDomainMatch_found() throws Exception {
|
||||||
|
login("evilregistrar");
|
||||||
runSuccessfulTestWithCatLol(RequestType.NAME, "cat.lol", "rdap_domain.json");
|
runSuccessfulTestWithCatLol(RequestType.NAME, "cat.lol", "rdap_domain.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDomainMatch_foundWithUpperCase() throws Exception {
|
public void testDomainMatch_foundWithUpperCase() throws Exception {
|
||||||
|
login("evilregistrar");
|
||||||
runSuccessfulTestWithCatLol(RequestType.NAME, "CaT.lOl", "rdap_domain.json");
|
runSuccessfulTestWithCatLol(RequestType.NAME, "CaT.lOl", "rdap_domain.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDomainMatch_found_sameRegistrarRequested() throws Exception {
|
||||||
|
login("evilregistrar");
|
||||||
|
action.registrarParam = Optional.of("evilregistrar");
|
||||||
|
runSuccessfulTestWithCatLol(RequestType.NAME, "cat.lol", "rdap_domain.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDomainMatch_notFound_differentRegistrarRequested() throws Exception {
|
||||||
|
action.registrarParam = Optional.of("otherregistrar");
|
||||||
|
runNotFoundTest(RequestType.NAME, "cat.lol", "No domains found");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDomainMatch_found_asAdministrator() throws Exception {
|
public void testDomainMatch_found_asAdministrator() throws Exception {
|
||||||
UserAuthInfo adminUserAuthInfo = UserAuthInfo.create(user, true);
|
loginAsAdmin();
|
||||||
action.authResult = AuthResult.create(AuthLevel.USER, adminUserAuthInfo);
|
|
||||||
when(sessionUtils.checkRegistrarConsoleLogin(request, adminUserAuthInfo)).thenReturn(false);
|
|
||||||
when(sessionUtils.getRegistrarClientId(request)).thenReturn("noregistrar");
|
|
||||||
runSuccessfulTestWithCatLol(RequestType.NAME, "cat.lol", "rdap_domain.json");
|
runSuccessfulTestWithCatLol(RequestType.NAME, "cat.lol", "rdap_domain.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDomainMatch_found_loggedInAsOtherRegistrar() throws Exception {
|
public void testDomainMatch_found_loggedInAsOtherRegistrar() throws Exception {
|
||||||
when(sessionUtils.getRegistrarClientId(request)).thenReturn("otherregistrar");
|
login("otherregistrar");
|
||||||
runSuccessfulTestWithCatLol(
|
runSuccessfulTestWithCatLol(
|
||||||
RequestType.NAME, "cat.lol", "rdap_domain_no_contacts_with_remark.json");
|
RequestType.NAME, "cat.lol", "rdap_domain_no_contacts_with_remark.json");
|
||||||
}
|
}
|
||||||
|
@ -618,11 +735,13 @@ public class RdapDomainSearchActionTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDomainMatch_cat2_lol_found() throws Exception {
|
public void testDomainMatch_cat2_lol_found() throws Exception {
|
||||||
|
login("evilregistrar");
|
||||||
runSuccessfulTestWithCat2Lol(RequestType.NAME, "cat2.lol", "rdap_domain_cat2.json");
|
runSuccessfulTestWithCat2Lol(RequestType.NAME, "cat2.lol", "rdap_domain_cat2.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDomainMatch_cat_example_found() throws Exception {
|
public void testDomainMatch_cat_example_found() throws Exception {
|
||||||
|
login("evilregistrar");
|
||||||
runSuccessfulTest(
|
runSuccessfulTest(
|
||||||
RequestType.NAME,
|
RequestType.NAME,
|
||||||
"cat.example",
|
"cat.example",
|
||||||
|
@ -705,6 +824,11 @@ public class RdapDomainSearchActionTest {
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDomainMatch_qstar_lol_notFound() throws Exception {
|
||||||
|
runNotFoundTest(RequestType.NAME, "q*.lol", "No domains found");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDomainMatch_star_lol_found() throws Exception {
|
public void testDomainMatch_star_lol_found() throws Exception {
|
||||||
assertThat(generateActualJson(RequestType.NAME, "*.lol"))
|
assertThat(generateActualJson(RequestType.NAME, "*.lol"))
|
||||||
|
@ -712,6 +836,20 @@ public class RdapDomainSearchActionTest {
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDomainMatch_star_lol_found_sameRegistrarRequested() throws Exception {
|
||||||
|
action.registrarParam = Optional.of("evilregistrar");
|
||||||
|
assertThat(generateActualJson(RequestType.NAME, "*.lol"))
|
||||||
|
.isEqualTo(generateExpectedJsonForTwoDomains("cat2.lol", "17-LOL", "cat.lol", "C-LOL"));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDomainMatch_star_lol_notFound_differentRegistrarRequested() throws Exception {
|
||||||
|
action.registrarParam = Optional.of("otherregistrar");
|
||||||
|
runNotFoundTest(RequestType.NAME, "*.lol", "No domains found");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDomainMatch_cat_star_found() throws Exception {
|
public void testDomainMatch_cat_star_found() throws Exception {
|
||||||
assertThat(generateActualJson(RequestType.NAME, "cat.*"))
|
assertThat(generateActualJson(RequestType.NAME, "cat.*"))
|
||||||
|
@ -725,8 +863,22 @@ public class RdapDomainSearchActionTest {
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDomainMatch_cat_star_foundOne_sameRegistrarRequested() throws Exception {
|
||||||
|
login("evilregistrar");
|
||||||
|
action.registrarParam = Optional.of("evilregistrar");
|
||||||
|
runSuccessfulTestWithCatLol(RequestType.NAME, "cat.*", "rdap_domain.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDomainMatch_cat_star_notFound_differentRegistrarRequested() throws Exception {
|
||||||
|
action.registrarParam = Optional.of("otherregistrar");
|
||||||
|
runNotFoundTest(RequestType.NAME, "cat.*", "No domains found");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDomainMatch_cat_lstar_found() throws Exception {
|
public void testDomainMatch_cat_lstar_found() throws Exception {
|
||||||
|
login("evilregistrar");
|
||||||
runSuccessfulTestWithCatLol(RequestType.NAME, "cat.l*", "rdap_domain.json");
|
runSuccessfulTestWithCatLol(RequestType.NAME, "cat.l*", "rdap_domain.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -763,6 +915,37 @@ public class RdapDomainSearchActionTest {
|
||||||
runNotFoundTest(RequestType.NAME, "cat.lol", "No domains found");
|
runNotFoundTest(RequestType.NAME, "cat.lol", "No domains found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDomainMatchDeletedDomain_notFound_deletedNotRequested() throws Exception {
|
||||||
|
login("evilregistrar");
|
||||||
|
persistDomainAsDeleted(domainCatLol, clock.nowUtc().minusDays(1));
|
||||||
|
runNotFoundTest(RequestType.NAME, "cat.lol", "No domains found");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDomainMatchDeletedDomain_found_loggedInAsSameRegistrar() throws Exception {
|
||||||
|
login("evilregistrar");
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
deleteCatLol();
|
||||||
|
runSuccessfulTestWithCatLol(RequestType.NAME, "cat.lol", "rdap_domain_deleted.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDomainMatchDeletedDomain_notFound_loggedInAsOtherRegistrar() throws Exception {
|
||||||
|
login("otherregistrar");
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
persistDomainAsDeleted(domainCatLol, clock.nowUtc().minusDays(1));
|
||||||
|
runNotFoundTest(RequestType.NAME, "cat.lol", "No domains found");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDomainMatchDeletedDomain_found_loggedInAsAdmin() throws Exception {
|
||||||
|
loginAsAdmin();
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
deleteCatLol();
|
||||||
|
runSuccessfulTestWithCatLol(RequestType.NAME, "cat.lol", "rdap_domain_deleted.json");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDomainMatchDeletedDomainWithWildcard_notFound() throws Exception {
|
public void testDomainMatchDeletedDomainWithWildcard_notFound() throws Exception {
|
||||||
persistDomainAsDeleted(domainCatLol, clock.nowUtc().minusDays(1));
|
persistDomainAsDeleted(domainCatLol, clock.nowUtc().minusDays(1));
|
||||||
|
@ -784,77 +967,6 @@ public class RdapDomainSearchActionTest {
|
||||||
runNotFoundTest(RequestType.NAME, "cat.lol", "No domains found");
|
runNotFoundTest(RequestType.NAME, "cat.lol", "No domains found");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createManyDomainsAndHosts(
|
|
||||||
int numActiveDomains, int numTotalDomainsPerActiveDomain, int numHosts) {
|
|
||||||
ImmutableSet.Builder<Key<HostResource>> hostKeysBuilder = new ImmutableSet.Builder<>();
|
|
||||||
ImmutableSet.Builder<String> subordinateHostsBuilder = new ImmutableSet.Builder<>();
|
|
||||||
String mainDomainName = String.format("domain%d.lol", numTotalDomainsPerActiveDomain);
|
|
||||||
for (int i = 1; i <= numHosts; i++) {
|
|
||||||
String hostName = String.format("ns%d.%s", i, mainDomainName);
|
|
||||||
subordinateHostsBuilder.add(hostName);
|
|
||||||
HostResource host = makeAndPersistHostResource(
|
|
||||||
hostName, String.format("5.5.%d.%d", 5 + i / 250, i % 250), clock.nowUtc().minusYears(1));
|
|
||||||
hostKeysBuilder.add(Key.create(host));
|
|
||||||
}
|
|
||||||
ImmutableSet<Key<HostResource>> hostKeys = hostKeysBuilder.build();
|
|
||||||
// Create all the domains at once, then persist them in parallel, for increased efficiency.
|
|
||||||
ImmutableList.Builder<DomainResource> domainsBuilder = new ImmutableList.Builder<>();
|
|
||||||
for (int i = 1; i <= numActiveDomains * numTotalDomainsPerActiveDomain; i++) {
|
|
||||||
String domainName = String.format("domain%d.lol", i);
|
|
||||||
DomainResource.Builder builder =
|
|
||||||
makeDomainResource(
|
|
||||||
domainName, contact1, contact2, contact3, null, null, registrar)
|
|
||||||
.asBuilder()
|
|
||||||
.setNameservers(hostKeys)
|
|
||||||
.setCreationTimeForTest(clock.nowUtc().minusYears(3));
|
|
||||||
if (domainName.equals(mainDomainName)) {
|
|
||||||
builder.setSubordinateHosts(subordinateHostsBuilder.build());
|
|
||||||
}
|
|
||||||
if (i % numTotalDomainsPerActiveDomain != 0) {
|
|
||||||
builder = builder.setDeletionTime(clock.nowUtc().minusDays(1));
|
|
||||||
}
|
|
||||||
domainsBuilder.add(builder.build());
|
|
||||||
}
|
|
||||||
persistResources(domainsBuilder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object readMultiDomainFile(
|
|
||||||
String fileName,
|
|
||||||
String domainName1,
|
|
||||||
String domainHandle1,
|
|
||||||
String domainName2,
|
|
||||||
String domainHandle2,
|
|
||||||
String domainName3,
|
|
||||||
String domainHandle3,
|
|
||||||
String domainName4,
|
|
||||||
String domainHandle4) {
|
|
||||||
return JSONValue.parse(loadFileWithSubstitutions(
|
|
||||||
this.getClass(),
|
|
||||||
fileName,
|
|
||||||
new ImmutableMap.Builder<String, String>()
|
|
||||||
.put("DOMAINNAME1", domainName1)
|
|
||||||
.put("DOMAINHANDLE1", domainHandle1)
|
|
||||||
.put("DOMAINNAME2", domainName2)
|
|
||||||
.put("DOMAINHANDLE2", domainHandle2)
|
|
||||||
.put("DOMAINNAME3", domainName3)
|
|
||||||
.put("DOMAINHANDLE3", domainHandle3)
|
|
||||||
.put("DOMAINNAME4", domainName4)
|
|
||||||
.put("DOMAINHANDLE4", domainHandle4)
|
|
||||||
.build()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkNumberOfDomainsInResult(Object obj, int expected) {
|
|
||||||
assertThat(obj).isInstanceOf(Map.class);
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
Map<String, Object> map = (Map<String, Object>) obj;
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
List<Object> domains = (List<Object>) map.get("domainSearchResults");
|
|
||||||
|
|
||||||
assertThat(domains).hasSize(expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDomainMatch_manyDeletedDomains_fullResultSet() throws Exception {
|
public void testDomainMatch_manyDeletedDomains_fullResultSet() throws Exception {
|
||||||
// There are enough domains to fill a full result set; deleted domains are ignored.
|
// There are enough domains to fill a full result set; deleted domains are ignored.
|
||||||
|
@ -972,25 +1084,54 @@ public class RdapDomainSearchActionTest {
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameserverMatch_foundMultiple_sameRegistrarRequested() throws Exception {
|
||||||
|
action.registrarParam = Optional.of("TheRegistrar");
|
||||||
|
assertThat(generateActualJson(RequestType.NS_LDH_NAME, "ns1.cat.lol"))
|
||||||
|
.isEqualTo(generateExpectedJsonForTwoDomains());
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameserverMatch_notFound_differentRegistrarRequested() throws Exception {
|
||||||
|
action.registrarParam = Optional.of("otherregistrar");
|
||||||
|
runNotFoundTest(RequestType.NS_LDH_NAME, "ns1.cat.lol", "No matching nameservers found");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNameserverMatchWithWildcard_found() throws Exception {
|
public void testNameserverMatchWithWildcard_found() throws Exception {
|
||||||
|
login("evilregistrar");
|
||||||
runSuccessfulTestWithCatLol(RequestType.NS_LDH_NAME, "ns2.cat.l*", "rdap_domain.json");
|
runSuccessfulTestWithCatLol(RequestType.NS_LDH_NAME, "ns2.cat.l*", "rdap_domain.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameserverMatchWithWildcard_found_sameRegistrarRequested() throws Exception {
|
||||||
|
login("evilregistrar");
|
||||||
|
action.registrarParam = Optional.of("TheRegistrar");
|
||||||
|
runSuccessfulTestWithCatLol(RequestType.NS_LDH_NAME, "ns2.cat.l*", "rdap_domain.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameserverMatchWithWildcard_notFound_differentRegistrarRequested()
|
||||||
|
throws Exception {
|
||||||
|
action.registrarParam = Optional.of("otherregistrar");
|
||||||
|
runNotFoundTest(RequestType.NS_LDH_NAME, "ns2.cat.l*", "No matching nameservers found");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNameserverMatchWithWildcardAndDomainSuffix_notFound() throws Exception {
|
public void testNameserverMatchWithWildcardAndDomainSuffix_notFound() throws Exception {
|
||||||
runNotFoundTest(RequestType.NS_LDH_NAME, "ns5*.cat.lol", "No matching nameservers found");
|
runNotFoundTest(RequestType.NS_LDH_NAME, "ns5*.cat.lol", "No matching nameservers found");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNameserverMatchWithNoPrefixWildcardAndDomainSuffix_found() throws Exception {
|
public void testNameserverMatchWithNoPrefixAndDomainSuffix_found() throws Exception {
|
||||||
assertThat(generateActualJson(RequestType.NS_LDH_NAME, "*.cat.lol"))
|
assertThat(generateActualJson(RequestType.NS_LDH_NAME, "*.cat.lol"))
|
||||||
.isEqualTo(generateExpectedJsonForTwoDomains());
|
.isEqualTo(generateExpectedJsonForTwoDomains());
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNameserverMatchWithOneCharacterPrefixWildcardAndDomainSuffix_found()
|
public void testNameserverMatchWithOneCharacterPrefixAndDomainSuffix_found()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
assertThat(generateActualJson(RequestType.NS_LDH_NAME, "n*.cat.lol"))
|
assertThat(generateActualJson(RequestType.NS_LDH_NAME, "n*.cat.lol"))
|
||||||
.isEqualTo(generateExpectedJsonForTwoDomains());
|
.isEqualTo(generateExpectedJsonForTwoDomains());
|
||||||
|
@ -998,7 +1139,24 @@ public class RdapDomainSearchActionTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNameserverMatchWithTwoCharacterPrefixWildcardAndDomainSuffix_found()
|
public void
|
||||||
|
testNameserverMatchWithOneCharacterPrefixAndDomainSuffix_found_sameRegistrarRequested()
|
||||||
|
throws Exception {
|
||||||
|
action.registrarParam = Optional.of("TheRegistrar");
|
||||||
|
assertThat(generateActualJson(RequestType.NS_LDH_NAME, "n*.cat.lol"))
|
||||||
|
.isEqualTo(generateExpectedJsonForTwoDomains());
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameserverMatchWithPrefixAndDomainSuffix_notFound_differentRegistrarRequested()
|
||||||
|
throws Exception {
|
||||||
|
action.registrarParam = Optional.of("otherregistrar");
|
||||||
|
runNotFoundTest(RequestType.NS_LDH_NAME, "n*.cat.lol", "No matching nameservers found");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameserverMatchWithTwoCharacterPrefixAndDomainSuffix_found()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
assertThat(generateActualJson(RequestType.NS_LDH_NAME, "ns*.cat.lol"))
|
assertThat(generateActualJson(RequestType.NS_LDH_NAME, "ns*.cat.lol"))
|
||||||
.isEqualTo(generateExpectedJsonForTwoDomains());
|
.isEqualTo(generateExpectedJsonForTwoDomains());
|
||||||
|
@ -1019,11 +1177,13 @@ public class RdapDomainSearchActionTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNameserverMatch_ns2_cat_lol_found() throws Exception {
|
public void testNameserverMatch_ns2_cat_lol_found() throws Exception {
|
||||||
|
login("evilregistrar");
|
||||||
runSuccessfulTestWithCatLol(RequestType.NS_LDH_NAME, "ns2.cat.lol", "rdap_domain.json");
|
runSuccessfulTestWithCatLol(RequestType.NS_LDH_NAME, "ns2.cat.lol", "rdap_domain.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNameserverMatch_ns2_dog_lol_found() throws Exception {
|
public void testNameserverMatch_ns2_dog_lol_found() throws Exception {
|
||||||
|
login("evilregistrar");
|
||||||
runSuccessfulTestWithCat2Lol(RequestType.NS_LDH_NAME, "ns2.dog.lol", "rdap_domain_cat2.json");
|
runSuccessfulTestWithCat2Lol(RequestType.NS_LDH_NAME, "ns2.dog.lol", "rdap_domain_cat2.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1092,8 +1252,41 @@ public class RdapDomainSearchActionTest {
|
||||||
runNotFoundTest(RequestType.NS_LDH_NAME, "ns2.cat.lol", "No matching nameservers found");
|
runNotFoundTest(RequestType.NS_LDH_NAME, "ns2.cat.lol", "No matching nameservers found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameserverMatchDeletedDomain_notFound() throws Exception {
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
deleteCatLol();
|
||||||
|
runNotFoundTest(RequestType.NS_LDH_NAME, "ns2.cat.lol", "No domains found");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameserverMatchDeletedDomain_found_loggedInAsSameRegistrar() throws Exception {
|
||||||
|
login("evilregistrar");
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
deleteCatLol();
|
||||||
|
runSuccessfulTestWithCatLol(RequestType.NS_LDH_NAME, "ns2.cat.lol", "rdap_domain_deleted.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameserverMatchDeletedDomain_notFound_loggedInAsOtherRegistrar()
|
||||||
|
throws Exception {
|
||||||
|
login("otherregistrar");
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
persistDomainAsDeleted(domainCatLol, clock.nowUtc().minusDays(1));
|
||||||
|
runNotFoundTest(RequestType.NS_LDH_NAME, "ns2.cat.lol", "No domains found");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameserverMatchDeletedDomain_found_loggedInAsAdmin() throws Exception {
|
||||||
|
loginAsAdmin();
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
deleteCatLol();
|
||||||
|
runSuccessfulTestWithCatLol(RequestType.NS_LDH_NAME, "ns2.cat.lol", "rdap_domain_deleted.json");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNameserverMatchOneDeletedDomain_foundTheOther() throws Exception {
|
public void testNameserverMatchOneDeletedDomain_foundTheOther() throws Exception {
|
||||||
|
login("evilregistrar");
|
||||||
persistDomainAsDeleted(domainCatExample, clock.nowUtc().minusDays(1));
|
persistDomainAsDeleted(domainCatExample, clock.nowUtc().minusDays(1));
|
||||||
runSuccessfulTestWithCatLol(RequestType.NS_LDH_NAME, "ns1.cat.lol", "rdap_domain.json");
|
runSuccessfulTestWithCatLol(RequestType.NS_LDH_NAME, "ns1.cat.lol", "rdap_domain.json");
|
||||||
}
|
}
|
||||||
|
@ -1254,12 +1447,27 @@ public class RdapDomainSearchActionTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddressMatchV6Address_foundMultiple() throws Exception {
|
public void testAddressMatchV4Address_foundMultiple_sameRegistrarRequested() throws Exception {
|
||||||
assertThat(generateActualJson(RequestType.NS_IP, "bad:f00d:cafe:0:0:0:15:beef"))
|
action.registrarParam = Optional.of("TheRegistrar");
|
||||||
|
assertThat(generateActualJson(RequestType.NS_IP, "1.2.3.4"))
|
||||||
.isEqualTo(generateExpectedJsonForTwoDomains());
|
.isEqualTo(generateExpectedJsonForTwoDomains());
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressMatchV4Address_notFound_differentRegistrarRequested() throws Exception {
|
||||||
|
action.registrarParam = Optional.of("otherregistrar");
|
||||||
|
runNotFoundTest(RequestType.NS_IP, "1.2.3.4", "No domains found");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressMatchV6Address_foundOne() throws Exception {
|
||||||
|
runSuccessfulTestWithCatLol(
|
||||||
|
RequestType.NS_IP,
|
||||||
|
"bad:f00d:cafe:0:0:0:15:beef",
|
||||||
|
"rdap_domain_no_contacts_with_remark.json");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddressMatchLocalhost_notFound() throws Exception {
|
public void testAddressMatchLocalhost_notFound() throws Exception {
|
||||||
runNotFoundTest(RequestType.NS_IP, "127.0.0.1", "No domains found");
|
runNotFoundTest(RequestType.NS_IP, "127.0.0.1", "No domains found");
|
||||||
|
@ -1274,8 +1482,42 @@ public class RdapDomainSearchActionTest {
|
||||||
runNotFoundTest(RequestType.NS_IP, "127.0.0.1", "No matching nameservers found");
|
runNotFoundTest(RequestType.NS_IP, "127.0.0.1", "No matching nameservers found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressMatchDeletedDomain_notFound() throws Exception {
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
deleteCatLol();
|
||||||
|
runNotFoundTest(RequestType.NS_IP, "bad:f00d:cafe:0:0:0:15:beef", "No domains found");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressMatchDeletedDomain_found_loggedInAsSameRegistrar() throws Exception {
|
||||||
|
login("evilregistrar");
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
deleteCatLol();
|
||||||
|
runSuccessfulTestWithCatLol(
|
||||||
|
RequestType.NS_IP, "bad:f00d:cafe:0:0:0:15:beef", "rdap_domain_deleted.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressMatchDeletedDomain_notFound_loggedInAsOtherRegistrar() throws Exception {
|
||||||
|
login("otherregistrar");
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
persistDomainAsDeleted(domainCatLol, clock.nowUtc().minusDays(1));
|
||||||
|
runNotFoundTest(RequestType.NS_IP, "bad:f00d:cafe:0:0:0:15:beef", "No domains found");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressMatchDeletedDomain_found_loggedInAsAdmin() throws Exception {
|
||||||
|
loginAsAdmin();
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
deleteCatLol();
|
||||||
|
runSuccessfulTestWithCatLol(
|
||||||
|
RequestType.NS_IP, "bad:f00d:cafe:0:0:0:15:beef", "rdap_domain_deleted.json");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddressMatchOneDeletedDomain_foundTheOther() throws Exception {
|
public void testAddressMatchOneDeletedDomain_foundTheOther() throws Exception {
|
||||||
|
login("evilregistrar");
|
||||||
persistDomainAsDeleted(domainCatExample, clock.nowUtc().minusDays(1));
|
persistDomainAsDeleted(domainCatExample, clock.nowUtc().minusDays(1));
|
||||||
assertThat(generateActualJson(RequestType.NS_IP, "1.2.3.4"))
|
assertThat(generateActualJson(RequestType.NS_IP, "1.2.3.4"))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
|
|
|
@ -75,8 +75,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"status": [
|
"status": [
|
||||||
"active",
|
"active"
|
||||||
"associated"
|
|
||||||
],
|
],
|
||||||
"handle": "%NAMESERVER2ROID%",
|
"handle": "%NAMESERVER2ROID%",
|
||||||
"links": [
|
"links": [
|
||||||
|
@ -111,8 +110,7 @@
|
||||||
"entities": [
|
"entities": [
|
||||||
{
|
{
|
||||||
"status": [
|
"status": [
|
||||||
"active",
|
"active"
|
||||||
"associated"
|
|
||||||
],
|
],
|
||||||
"handle": "%CONTACT1ROID%",
|
"handle": "%CONTACT1ROID%",
|
||||||
"roles": [
|
"roles": [
|
||||||
|
@ -204,8 +202,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"status": [
|
"status": [
|
||||||
"active",
|
"active"
|
||||||
"associated"
|
|
||||||
],
|
],
|
||||||
"handle": "%CONTACT2ROID%",
|
"handle": "%CONTACT2ROID%",
|
||||||
"roles": [
|
"roles": [
|
||||||
|
@ -297,8 +294,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"status": [
|
"status": [
|
||||||
"active",
|
"active"
|
||||||
"associated"
|
|
||||||
],
|
],
|
||||||
"handle": "%CONTACT3ROID%",
|
"handle": "%CONTACT3ROID%",
|
||||||
"roles": [
|
"roles": [
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue