mirror of
https://github.com/google/nomulus
synced 2025-12-23 06:15:42 +00:00
Add BSA label to rdap-domain 404 responses for BSA domains (#2706)
This commit is contained in:
@@ -199,16 +199,16 @@ public class Tld extends ImmutableObject implements Buildable, UnsafeSerializabl
|
||||
|
||||
/** Returns the TLD entities for the given TLD strings, throwing if any don't exist. */
|
||||
public static ImmutableSet<Tld> get(Set<String> tlds) {
|
||||
Map<String, Optional<Tld>> registries = CACHE.getAll(tlds);
|
||||
ImmutableSet<String> missingRegistries =
|
||||
registries.entrySet().stream()
|
||||
Map<String, Optional<Tld>> tldObjects = CACHE.getAll(tlds);
|
||||
ImmutableSet<String> missingTlds =
|
||||
tldObjects.entrySet().stream()
|
||||
.filter(e -> e.getValue().isEmpty())
|
||||
.map(Map.Entry::getKey)
|
||||
.collect(toImmutableSet());
|
||||
if (missingRegistries.isEmpty()) {
|
||||
return registries.values().stream().map(Optional::get).collect(toImmutableSet());
|
||||
if (missingTlds.isEmpty()) {
|
||||
return tldObjects.values().stream().map(Optional::get).collect(toImmutableSet());
|
||||
} else {
|
||||
throw new TldNotFoundException(missingRegistries);
|
||||
throw new TldNotFoundException(missingTlds);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
|
||||
package google.registry.model.tld.label;
|
||||
|
||||
import static com.google.common.base.Charsets.US_ASCII;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static com.google.common.hash.Funnels.stringFunnel;
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
// limitations under the License.
|
||||
package google.registry.persistence.converter;
|
||||
|
||||
import static com.google.common.base.Charsets.US_ASCII;
|
||||
import static com.google.common.hash.Funnels.stringFunnel;
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
|
||||
import com.google.common.hash.BloomFilter;
|
||||
import jakarta.persistence.AttributeConverter;
|
||||
|
||||
@@ -14,14 +14,15 @@
|
||||
|
||||
package google.registry.rdap;
|
||||
|
||||
import static com.google.common.base.Charsets.UTF_8;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.net.HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN;
|
||||
import static google.registry.request.Actions.getPathForAction;
|
||||
import static google.registry.util.DomainNameUtils.canonicalizeHostname;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_NOT_FOUND;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.net.MediaType;
|
||||
@@ -41,6 +42,7 @@ import google.registry.request.Parameter;
|
||||
import google.registry.request.RequestMethod;
|
||||
import google.registry.request.RequestPath;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.util.Clock;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Optional;
|
||||
@@ -60,6 +62,10 @@ public abstract class RdapActionBase implements Runnable {
|
||||
private static final MediaType RESPONSE_MEDIA_TYPE =
|
||||
MediaType.create("application", "rdap+json").withCharset(UTF_8);
|
||||
|
||||
private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create();
|
||||
private static final Gson FORMATTED_OUTPUT_GSON =
|
||||
new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create();
|
||||
|
||||
/** Whether to include or exclude deleted items from a query. */
|
||||
protected enum DeletedItemHandling {
|
||||
EXCLUDE,
|
||||
@@ -75,6 +81,7 @@ public abstract class RdapActionBase implements Runnable {
|
||||
@Inject @Parameter("formatOutput") Optional<Boolean> formatOutputParam;
|
||||
@Inject @Config("rdapResultSetMaxSize") int rdapResultSetMaxSize;
|
||||
@Inject RdapMetrics rdapMetrics;
|
||||
@Inject Clock clock;
|
||||
|
||||
/** Builder for metric recording. */
|
||||
final RdapMetrics.RdapMetricInformation.Builder metricInformationBuilder =
|
||||
@@ -152,6 +159,10 @@ public abstract class RdapActionBase implements Runnable {
|
||||
response.setStatus(SC_OK);
|
||||
setPayload(replyObject);
|
||||
metricInformationBuilder.setStatusCode(SC_OK);
|
||||
} catch (RdapDomainAction.DomainBlockedByBsaException e) {
|
||||
logger.atInfo().withCause(e).log("Domain blocked by BSA");
|
||||
setErrorCodes(SC_NOT_FOUND);
|
||||
setPayload(new RdapObjectClasses.DomainBlockedByBsaErrorResponse(e.getMessage()));
|
||||
} catch (HttpException e) {
|
||||
logger.atInfo().withCause(e).log("Error in RDAP.");
|
||||
setError(e.getResponseCode(), e.getResponseCodeString(), e.getMessage());
|
||||
@@ -166,8 +177,7 @@ public abstract class RdapActionBase implements Runnable {
|
||||
}
|
||||
|
||||
void setError(int status, String title, String description) {
|
||||
metricInformationBuilder.setStatusCode(status);
|
||||
response.setStatus(status);
|
||||
setErrorCodes(status);
|
||||
try {
|
||||
setPayload(ErrorResponse.create(status, title, description));
|
||||
} catch (Exception ex) {
|
||||
@@ -176,21 +186,18 @@ public abstract class RdapActionBase implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
void setErrorCodes(int status) {
|
||||
metricInformationBuilder.setStatusCode(status);
|
||||
response.setStatus(status);
|
||||
}
|
||||
|
||||
void setPayload(ReplyPayloadBase replyObject) {
|
||||
if (requestMethod == Action.Method.HEAD) {
|
||||
return;
|
||||
}
|
||||
|
||||
GsonBuilder gsonBuilder = new GsonBuilder();
|
||||
gsonBuilder.disableHtmlEscaping();
|
||||
if (formatOutputParam.orElse(false)) {
|
||||
gsonBuilder.setPrettyPrinting();
|
||||
}
|
||||
Gson gson = gsonBuilder.create();
|
||||
|
||||
TopLevelReplyObject topLevelObject =
|
||||
TopLevelReplyObject.create(replyObject, rdapJsonFormatter.createTosNotice());
|
||||
|
||||
Gson gson = formatOutputParam.orElse(false) ? FORMATTED_OUTPUT_GSON : GSON;
|
||||
response.setPayload(gson.toJson(topLevelObject.toJson()));
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ final class RdapDataStructures {
|
||||
*/
|
||||
@AutoValue
|
||||
@RestrictJsonNames("notices[]")
|
||||
abstract static class Notice extends NoticeOrRemark {
|
||||
public abstract static class Notice extends NoticeOrRemark {
|
||||
|
||||
/**
|
||||
* Notice and Remark Type are defined in 10.2.1 of RFC 9083.
|
||||
|
||||
@@ -20,8 +20,11 @@ import static google.registry.request.Action.Method.GET;
|
||||
import static google.registry.request.Action.Method.HEAD;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
|
||||
import com.google.common.net.InternetDomainName;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.domain.DomainFlowUtils;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.tld.Tld;
|
||||
import google.registry.rdap.RdapJsonFormatter.OutputDataType;
|
||||
import google.registry.rdap.RdapMetrics.EndpointType;
|
||||
import google.registry.rdap.RdapObjectClasses.RdapDomain;
|
||||
@@ -51,8 +54,9 @@ public class RdapDomainAction extends RdapActionBase {
|
||||
// RDAP Technical Implementation Guide 2.1.1 - we must support A-label (Punycode) and U-label
|
||||
// (Unicode) formats. canonicalizeName will transform Unicode to Punycode so we support both.
|
||||
pathSearchString = canonicalizeName(pathSearchString);
|
||||
InternetDomainName domainName;
|
||||
try {
|
||||
validateDomainName(pathSearchString);
|
||||
domainName = validateDomainName(pathSearchString);
|
||||
} catch (EppException e) {
|
||||
throw new BadRequestException(
|
||||
String.format(
|
||||
@@ -66,6 +70,7 @@ public class RdapDomainAction extends RdapActionBase {
|
||||
pathSearchString,
|
||||
shouldIncludeDeleted() ? START_OF_TIME : rdapJsonFormatter.getRequestTime());
|
||||
if (domain.isEmpty() || !isAuthorized(domain.get())) {
|
||||
handlePossibleBsaBlock(domainName);
|
||||
// RFC7480 5.3 - if the server wishes to respond that it doesn't have data satisfying the
|
||||
// query, it MUST reply with 404 response code.
|
||||
//
|
||||
@@ -75,4 +80,17 @@ public class RdapDomainAction extends RdapActionBase {
|
||||
}
|
||||
return rdapJsonFormatter.createRdapDomain(domain.get(), OutputDataType.FULL);
|
||||
}
|
||||
|
||||
private void handlePossibleBsaBlock(InternetDomainName domainName) {
|
||||
Tld tld = Tld.get(domainName.parent().toString());
|
||||
if (DomainFlowUtils.isBlockedByBsa(domainName.parts().getFirst(), tld, clock.nowUtc())) {
|
||||
throw new DomainBlockedByBsaException(domainName + " blocked by BSA");
|
||||
}
|
||||
}
|
||||
|
||||
static class DomainBlockedByBsaException extends RuntimeException {
|
||||
DomainBlockedByBsaException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,8 +63,21 @@ public class RdapIcannStandardInformation {
|
||||
.build())
|
||||
.build();
|
||||
|
||||
/** Not required, but provided when a domain is blocked by BSA. */
|
||||
private static final Notice DOMAIN_BLOCKED_BY_BSA_NOTICE =
|
||||
Notice.builder()
|
||||
.setTitle("Blocked Domain")
|
||||
.setDescription("This name has been blocked by a GlobalBlock service")
|
||||
.addLink(
|
||||
Link.builder()
|
||||
.setRel("alternate")
|
||||
.setHref("https://brandsafetyalliance.co")
|
||||
.setType("text/html")
|
||||
.build())
|
||||
.build();
|
||||
|
||||
/** Boilerplate notices required by domain responses. */
|
||||
static final ImmutableList<Notice> domainBoilerplateNotices =
|
||||
static final ImmutableList<Notice> DOMAIN_BOILERPLATE_NOTICES =
|
||||
ImmutableList.of(
|
||||
CONFORMANCE_NOTICE,
|
||||
// RDAP Response Profile 2.6.3
|
||||
@@ -72,8 +85,12 @@ public class RdapIcannStandardInformation {
|
||||
// RDAP Response Profile 2.11
|
||||
INACCURACY_COMPLAINT_FORM_NOTICE);
|
||||
|
||||
/** Boilerplate notice for when a domain is blocked by BSA. */
|
||||
static final ImmutableList<Notice> DOMAIN_BLOCKED_BY_BSA_BOILERPLATE_NOTICES =
|
||||
ImmutableList.of(DOMAIN_BLOCKED_BY_BSA_NOTICE);
|
||||
|
||||
/** Boilerplate remarks required by nameserver and entity responses. */
|
||||
static final ImmutableList<Notice> nameserverAndEntityBoilerplateNotices =
|
||||
static final ImmutableList<Notice> NAMESERVER_AND_ENTITY_BOILERPLATE_NOTICES =
|
||||
ImmutableList.of(CONFORMANCE_NOTICE);
|
||||
|
||||
/**
|
||||
|
||||
@@ -39,6 +39,7 @@ import google.registry.rdap.RdapDataStructures.RdapConformance;
|
||||
import google.registry.rdap.RdapDataStructures.RdapStatus;
|
||||
import google.registry.rdap.RdapDataStructures.Remark;
|
||||
import google.registry.util.Idn;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.util.Optional;
|
||||
|
||||
/** Object Classes defined in RFC 9083 section 5. */
|
||||
@@ -137,10 +138,22 @@ final class RdapObjectClasses {
|
||||
* suppress them for other types of responses (e.g. help).
|
||||
*/
|
||||
public enum BoilerplateType {
|
||||
DOMAIN,
|
||||
NAMESERVER,
|
||||
ENTITY,
|
||||
OTHER
|
||||
DOMAIN(RdapIcannStandardInformation.DOMAIN_BOILERPLATE_NOTICES),
|
||||
DOMAIN_BLOCKED_BY_BSA(RdapIcannStandardInformation.DOMAIN_BLOCKED_BY_BSA_BOILERPLATE_NOTICES),
|
||||
NAMESERVER(RdapIcannStandardInformation.NAMESERVER_AND_ENTITY_BOILERPLATE_NOTICES),
|
||||
ENTITY(RdapIcannStandardInformation.NAMESERVER_AND_ENTITY_BOILERPLATE_NOTICES),
|
||||
OTHER(ImmutableList.of());
|
||||
|
||||
@SuppressWarnings("ImmutableEnumChecker") // immutable lists are, in fact, immutable
|
||||
private final ImmutableList<Notice> notices;
|
||||
|
||||
BoilerplateType(ImmutableList<Notice> notices) {
|
||||
this.notices = notices;
|
||||
}
|
||||
|
||||
public ImmutableList<Notice> getNotices() {
|
||||
return notices;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,14 +186,7 @@ final class RdapObjectClasses {
|
||||
@JsonableElement("notices[]") abstract Notice aTosNotice();
|
||||
|
||||
@JsonableElement("notices") ImmutableList<Notice> boilerplateNotices() {
|
||||
return switch (aAreplyObject().boilerplateType) {
|
||||
case DOMAIN -> RdapIcannStandardInformation.domainBoilerplateNotices;
|
||||
case NAMESERVER, ENTITY ->
|
||||
RdapIcannStandardInformation.nameserverAndEntityBoilerplateNotices;
|
||||
default -> // things other than domains, nameservers and entities do not yet have
|
||||
// boilerplate
|
||||
ImmutableList.of();
|
||||
};
|
||||
return aAreplyObject().boilerplateType.getNotices();
|
||||
}
|
||||
|
||||
static TopLevelReplyObject create(ReplyPayloadBase replyObject, Notice tosNotice) {
|
||||
@@ -532,6 +538,25 @@ final class RdapObjectClasses {
|
||||
}
|
||||
}
|
||||
|
||||
/** Specialized error response body for when a domain is blocked by BSA. */
|
||||
@RestrictJsonNames({})
|
||||
@SuppressWarnings("UnusedVariable")
|
||||
public static class DomainBlockedByBsaErrorResponse extends ReplyPayloadBase {
|
||||
|
||||
@JsonableElement private static final LanguageIdentifier lang = LanguageIdentifier.EN;
|
||||
|
||||
@JsonableElement private static final int errorCode = HttpServletResponse.SC_NOT_FOUND;
|
||||
|
||||
@JsonableElement private static final String title = "Not Found";
|
||||
|
||||
@JsonableElement private final ImmutableList<String> description;
|
||||
|
||||
DomainBlockedByBsaErrorResponse(String message) {
|
||||
super(BoilerplateType.DOMAIN_BLOCKED_BY_BSA);
|
||||
this.description = ImmutableList.of(message);
|
||||
}
|
||||
}
|
||||
|
||||
/** Error Response Body defined in 6 of RFC 9083. */
|
||||
@RestrictJsonNames({})
|
||||
@AutoValue
|
||||
|
||||
@@ -27,7 +27,7 @@ import java.util.List;
|
||||
* @param numResourcesRetrieved Number of resources retrieved from the database in the process of
|
||||
* assembling the data set.
|
||||
*/
|
||||
record RdapResultSet<T extends EppResource>(
|
||||
public record RdapResultSet<T extends EppResource>(
|
||||
ImmutableList<T> resources,
|
||||
IncompletenessWarningType incompletenessWarningType,
|
||||
int numResourcesRetrieved) {
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
|
||||
package google.registry.rdap;
|
||||
|
||||
import static com.google.common.base.Charsets.UTF_8;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.replicaTm;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
@@ -69,7 +69,7 @@ public abstract class RdapSearchActionBase extends RdapActionBase {
|
||||
public final BaseSearchResponse getJsonObjectForResource(
|
||||
String pathSearchString, boolean isHeadRequest) {
|
||||
// The pathSearchString is not used by search commands.
|
||||
if (pathSearchString.length() > 0) {
|
||||
if (!pathSearchString.isEmpty()) {
|
||||
throw new BadRequestException("Unexpected path");
|
||||
}
|
||||
decodeCursorToken();
|
||||
@@ -323,7 +323,8 @@ public abstract class RdapSearchActionBase extends RdapActionBase {
|
||||
if (partialStringQuery.getHasWildcard()) {
|
||||
builder =
|
||||
builder.where(
|
||||
filterField, criteriaBuilder::like,
|
||||
filterField,
|
||||
criteriaBuilder::like,
|
||||
String.format("%s%%", partialStringQuery.getInitialString()));
|
||||
} else {
|
||||
// no wildcard means we use a standard equals query
|
||||
|
||||
@@ -40,7 +40,7 @@ import java.util.Optional;
|
||||
abstract class RdapSearchResults {
|
||||
|
||||
/** Responding To Searches defined in 8 of RFC 9083. */
|
||||
abstract static class BaseSearchResponse extends ReplyPayloadBase {
|
||||
public abstract static class BaseSearchResponse extends ReplyPayloadBase {
|
||||
abstract IncompletenessWarningType incompletenessWarningType();
|
||||
abstract ImmutableMap<String, URI> navigationLinks();
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.google.common.flogger.FluentLogger;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Base for exceptions that cause an HTTP error response. */
|
||||
public abstract class HttpException extends RuntimeException {
|
||||
@@ -33,13 +34,14 @@ public abstract class HttpException extends RuntimeException {
|
||||
|
||||
private final int responseCode;
|
||||
|
||||
protected HttpException(int responseCode, String message, Throwable cause, Level logLevel) {
|
||||
protected HttpException(
|
||||
int responseCode, String message, @Nullable Throwable cause, Level logLevel) {
|
||||
super(message, cause);
|
||||
this.responseCode = responseCode;
|
||||
this.logLevel = logLevel;
|
||||
}
|
||||
|
||||
protected HttpException(int responseCode, String message, Throwable cause) {
|
||||
protected HttpException(int responseCode, String message, @Nullable Throwable cause) {
|
||||
this(responseCode, message, cause, Level.INFO);
|
||||
}
|
||||
|
||||
@@ -117,22 +119,6 @@ public abstract class HttpException extends RuntimeException {
|
||||
}
|
||||
}
|
||||
|
||||
/** Exception that causes a 403 response. */
|
||||
public static final class ForbiddenException extends HttpException {
|
||||
public ForbiddenException(String message) {
|
||||
super(HttpServletResponse.SC_FORBIDDEN, message, null);
|
||||
}
|
||||
|
||||
public ForbiddenException(String message, Exception cause) {
|
||||
super(HttpServletResponse.SC_FORBIDDEN, message, cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResponseCodeString() {
|
||||
return "Forbidden";
|
||||
}
|
||||
}
|
||||
|
||||
/** Exception that causes a 404 response. */
|
||||
public static final class NotFoundException extends HttpException {
|
||||
public NotFoundException() {
|
||||
@@ -149,18 +135,6 @@ public abstract class HttpException extends RuntimeException {
|
||||
}
|
||||
}
|
||||
|
||||
/** Exception that causes a 405 response. */
|
||||
public static final class MethodNotAllowedException extends HttpException {
|
||||
public MethodNotAllowedException() {
|
||||
super(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "Method not allowed", null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResponseCodeString() {
|
||||
return "Method Not Allowed";
|
||||
}
|
||||
}
|
||||
|
||||
/** Exception that causes a 409 response. */
|
||||
public static final class ConflictException extends HttpException {
|
||||
public ConflictException(String message) {
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
// limitations under the License.
|
||||
package google.registry.persistence.converter;
|
||||
|
||||
import static com.google.common.base.Charsets.US_ASCII;
|
||||
import static com.google.common.hash.Funnels.stringFunnel;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.testing.DatabaseHelper.insertInDb;
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.hash.BloomFilter;
|
||||
|
||||
@@ -21,7 +21,6 @@ import static google.registry.testing.DatabaseHelper.insertSimpleResources;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.testcontainers.containers.PostgreSQLContainer.POSTGRESQL_PORT;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -305,7 +304,7 @@ public abstract class JpaTransactionManagerExtension
|
||||
|
||||
private static String readSqlInClassPath(String sqlScriptPath) {
|
||||
try {
|
||||
return Resources.toString(Resources.getResource(sqlScriptPath), Charsets.UTF_8);
|
||||
return Resources.toString(Resources.getResource(sqlScriptPath), UTF_8);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@ abstract class RdapActionBaseTestCase<A extends RdapActionBase> {
|
||||
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter(clock);
|
||||
action.rdapMetrics = rdapMetrics;
|
||||
action.requestMethod = GET;
|
||||
action.clock = new FakeClock(DateTime.parse("2025-01-01T00:00:00.000Z"));
|
||||
logout();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package google.registry.rdap;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.bsa.persistence.BsaTestingUtils.persistBsaLabel;
|
||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
|
||||
@@ -27,8 +28,11 @@ import static google.registry.testing.FullFieldsTestEntityHelper.makeHistoryEntr
|
||||
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrar;
|
||||
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrarPocs;
|
||||
import static google.registry.testing.GsonSubject.assertAboutJson;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.gson.JsonObject;
|
||||
import google.registry.model.contact.Contact;
|
||||
@@ -608,6 +612,34 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBlockedByBsa() {
|
||||
persistResource(
|
||||
Tld.get("lol").asBuilder().setBsaEnrollStartTime(Optional.of(START_OF_TIME)).build());
|
||||
persistBsaLabel("example");
|
||||
ImmutableMap<?, ?> expectedBsaNotice =
|
||||
ImmutableMap.of(
|
||||
"description",
|
||||
ImmutableList.of("This name has been blocked by a GlobalBlock service"),
|
||||
"title",
|
||||
"Blocked Domain",
|
||||
"links",
|
||||
ImmutableList.of(
|
||||
ImmutableMap.of(
|
||||
"href",
|
||||
"https://brandsafetyalliance.co",
|
||||
"rel",
|
||||
"alternate",
|
||||
"type",
|
||||
"text/html")));
|
||||
JsonObject expectedErrorResponse = generateExpectedJsonError("example.lol blocked by BSA", 404);
|
||||
expectedErrorResponse
|
||||
.getAsJsonArray("notices")
|
||||
.add(RdapTestHelper.GSON.toJsonTree(expectedBsaNotice));
|
||||
assertAboutJson().that(generateActualJson("example.lol")).isEqualTo(expectedErrorResponse);
|
||||
assertThat(response.getStatus()).isEqualTo(404);
|
||||
}
|
||||
|
||||
private Domain persistActiveDomainWithHost(
|
||||
String label, String tld, DateTime creationTime, DateTime expirationTime) {
|
||||
return persistResource(
|
||||
|
||||
@@ -33,8 +33,7 @@ import java.util.Map;
|
||||
/** Test helper methods for RDAP tests. */
|
||||
class RdapTestHelper {
|
||||
|
||||
private static final Gson GSON =
|
||||
new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
|
||||
static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
|
||||
|
||||
static JsonElement createJson(String... lines) {
|
||||
return GSON.fromJson(Joiner.on("\n").join(lines), JsonElement.class);
|
||||
@@ -240,5 +239,4 @@ class RdapTestHelper {
|
||||
obj.remove("rdapConformance");
|
||||
return reply;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user