1
0
mirror of https://github.com/google/nomulus synced 2026-05-23 16:21:55 +00:00

Compare commits

...

5 Commits

Author SHA1 Message Date
Weimin Yu
9eddecf70f Bypass config check for caching when safe (#2773)
Pubapi actions should always use cache, regardless of the config
settings on caching.

In EppResource.java, the original `loadCached(Iterable<VKey>)`
method is renamed to `loadByCacheIfEnabled`. The original
`loadCached(Vkey)` method is renamed to `loadByCache` and always
uses cache.

In EppResourceUtils.java, the original `loadByForeignKeyCached`
method is renamed to `loadByForeignKeyByCacheIfEnabled`. A new
`loadByForeignKeyByCache` method, which always uses cache.

In ForeighKeyUtils.java, the original `loadCached` method is
renamed to `loadByCacheIfEnabled`, and a new `loadCached` method
is added which always uses cache.

Also added a `getContactsFromReplica` method in Registrar,
for use by RDAP actions.
2025-06-20 21:25:02 +00:00
gbrodman
d4bcff0c31 Add password reset Java object (#2765)
A future PR will add the actions that save and use this object. That
future PR will also require loading RegistrarPoc objects given the
registrar ID, hence the change in that class.
2025-06-17 19:00:50 +00:00
Ben McIlwain
62065f88fb Remove spurious parenthesis in URS command output (#2767)
It was making the undo nomulus command look like this:

)nomulus ...
2025-06-16 20:23:48 +00:00
Pavlo Tkach
c9ac9437fd Add java code for RegitrarPoc id (#2770) 2025-06-14 17:37:11 +00:00
gbrodman
1f6a09182d Add some changes related to RDAP Feb 2024 profile (#2759)
This implements two type of changes:
1. changing the link type for things like the terms of service
2. adding the request URL to each and every link with the "value" field.
   This is a bit tricky to implement because the links are generated in
various places, but we can implement it by adding it to the results
after generation.

See b/418782147 for more information
2025-06-11 20:30:15 +00:00
104 changed files with 1904 additions and 1237 deletions

View File

@@ -24,7 +24,7 @@ export type contactType =
| 'LEGAL'
| 'MARKETING'
| 'TECH'
| 'RDAP';
| 'WHOIS';
type contactTypesToUserFriendlyTypes = { [type in contactType]: string };
@@ -35,7 +35,7 @@ export const contactTypeToTextMap: contactTypesToUserFriendlyTypes = {
LEGAL: 'Legal contact',
MARKETING: 'Marketing contact',
TECH: 'Technical contact',
RDAP: 'RDAP-Inquiry contact',
WHOIS: 'RDAP-Inquiry contact',
};
type UserFriendlyType = (typeof contactTypeToTextMap)[contactType];
@@ -59,7 +59,10 @@ export interface ViewReadyContact extends Contact {
export function contactTypeToViewReadyContact(c: Contact): ViewReadyContact {
return {
...c,
userFriendlyTypes: c.types?.map((cType) => contactTypeToTextMap[cType]),
userFriendlyTypes: (c.types || []).map(
(cType) => contactTypeToTextMap[cType]
),
types: c.types || [],
};
}
@@ -98,19 +101,21 @@ export class ContactService {
);
}
saveContacts(contacts: ViewReadyContact[]): Observable<Contact[]> {
updateContact(contact: ViewReadyContact) {
return this.backend
.postContacts(this.registrarService.registrarId(), contacts)
.updateContact(this.registrarService.registrarId(), contact)
.pipe(switchMap((_) => this.fetchContacts()));
}
addContact(contact: ViewReadyContact) {
const newContacts = this.contacts().concat([contact]);
return this.saveContacts(newContacts);
return this.backend
.createContact(this.registrarService.registrarId(), contact)
.pipe(switchMap((_) => this.fetchContacts()));
}
deleteContact(contact: ViewReadyContact) {
const newContacts = this.contacts().filter((c) => c !== contact);
return this.saveContacts(newContacts);
return this.backend
.deleteContact(this.registrarService.registrarId(), contact)
.pipe(switchMap((_) => this.fetchContacts()));
}
}

View File

@@ -69,9 +69,13 @@ export class ContactDetailsComponent {
save(e: SubmitEvent) {
e.preventDefault();
if ((this.contactService.contactInEdit.types || []).length === 0) {
this._snackBar.open('Required to select contact type');
return;
}
const request = this.contactService.isContactNewView
? this.contactService.addContact(this.contactService.contactInEdit)
: this.contactService.saveContacts(this.contactService.contacts());
: this.contactService.updateContact(this.contactService.contactInEdit);
request.subscribe({
complete: () => {
this.goBack();

View File

@@ -70,13 +70,26 @@ export class BackendService {
.pipe(catchError((err) => this.errorCatcher<Contact[]>(err)));
}
postContacts(
registrarId: string,
contacts: Contact[]
): Observable<Contact[]> {
return this.http.post<Contact[]>(
updateContact(registrarId: string, contact: Contact): Observable<Contact> {
return this.http.put<Contact>(
`/console-api/settings/contacts?registrarId=${registrarId}`,
contacts
contact
);
}
createContact(registrarId: string, contact: Contact): Observable<Contact> {
return this.http.post<Contact>(
`/console-api/settings/contacts?registrarId=${registrarId}`,
contact
);
}
deleteContact(registrarId: string, contact: Contact): Observable<Contact> {
return this.http.delete<Contact>(
`/console-api/settings/contacts?registrarId=${registrarId}`,
{
body: JSON.stringify(contact),
}
);
}

View File

@@ -185,7 +185,8 @@ public class CheckApiAction implements Runnable {
}
private boolean checkExists(String domainString, DateTime now) {
return !ForeignKeyUtils.loadCached(Domain.class, ImmutableList.of(domainString), now).isEmpty();
return !ForeignKeyUtils.loadByCache(Domain.class, ImmutableList.of(domainString), now)
.isEmpty();
}
private Optional<String> checkReserved(InternetDomainName domainName) {

View File

@@ -432,7 +432,7 @@ public final class DomainCheckFlow implements TransactionalFlow {
.filter(existingDomains::containsKey)
.collect(toImmutableMap(d -> d, existingDomains::get));
ImmutableMap<VKey<? extends EppResource>, EppResource> loadedDomains =
EppResource.loadCached(ImmutableList.copyOf(existingDomainsToLoad.values()));
EppResource.loadByCacheIfEnabled(ImmutableList.copyOf(existingDomainsToLoad.values()));
return ImmutableMap.copyOf(
Maps.transformEntries(existingDomainsToLoad, (k, v) -> (Domain) loadedDomains.get(v)));
}

View File

@@ -417,7 +417,7 @@ public class DomainFlowUtils {
contacts.stream().map(DesignatedContact::getContactKey).forEach(keysToLoad::add);
registrant.ifPresent(keysToLoad::add);
keysToLoad.addAll(nameservers);
verifyNotInPendingDelete(EppResource.loadCached(keysToLoad.build()).values());
verifyNotInPendingDelete(EppResource.loadByCacheIfEnabled(keysToLoad.build()).values());
}
private static void verifyNotInPendingDelete(Iterable<EppResource> resources)

View File

@@ -404,7 +404,7 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
* <p>Don't use this unless you really need it for performance reasons, and be sure that you are
* OK with the trade-offs in loss of transactional consistency.
*/
public static ImmutableMap<VKey<? extends EppResource>, EppResource> loadCached(
public static ImmutableMap<VKey<? extends EppResource>, EppResource> loadByCacheIfEnabled(
Iterable<VKey<? extends EppResource>> keys) {
if (!RegistryConfig.isEppResourceCachingEnabled()) {
return tm().reTransact(() -> tm().loadByKeys(keys));
@@ -413,15 +413,12 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
}
/**
* Loads a given EppResource by its key using the cache (if enabled).
* Loads a given EppResource by its key using the cache.
*
* <p>Don't use this unless you really need it for performance reasons, and be sure that you are
* OK with the trade-offs in loss of transactional consistency.
* <p>This method ignores the `isEppResourceCachingEnabled` config setting. It is reserved for use
* cases that can tolerate slightly stale data, e.g., RDAP queries.
*/
public static <T extends EppResource> T loadCached(VKey<T> key) {
if (!RegistryConfig.isEppResourceCachingEnabled()) {
return tm().reTransact(() -> tm().loadByKey(key));
}
public static <T extends EppResource> T loadByCache(VKey<T> key) {
// Safe to cast because loading a Key<T> returns an entity of type T.
@SuppressWarnings("unchecked")
T resource = (T) cacheEppResources.get(key);

View File

@@ -16,6 +16,7 @@ package google.registry.model;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static google.registry.persistence.transaction.TransactionManagerFactory.replicaTm;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static google.registry.util.DateTimeUtils.isAtOrAfter;
@@ -40,6 +41,7 @@ import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferStatus;
import google.registry.persistence.VKey;
import google.registry.persistence.transaction.TransactionManager;
import jakarta.persistence.Query;
import java.util.Collection;
import java.util.Comparator;
@@ -109,12 +111,12 @@ public final class EppResourceUtils {
*/
public static <T extends EppResource> Optional<T> loadByForeignKey(
Class<T> clazz, String foreignKey, DateTime now) {
return loadByForeignKeyHelper(clazz, foreignKey, now, false);
return loadByForeignKeyHelper(tm(), clazz, foreignKey, now, false);
}
/**
* Loads the last created version of an {@link EppResource} from the database by foreign key,
* using a cache.
* using a cache, if caching is enabled in config settings.
*
* <p>Returns null if no resource with this foreign key was ever created, or if the most recently
* created resource was deleted before time "now".
@@ -134,20 +136,36 @@ public final class EppResourceUtils {
* @param foreignKey id to match
* @param now the current logical time to project resources at
*/
public static <T extends EppResource> Optional<T> loadByForeignKeyCached(
public static <T extends EppResource> Optional<T> loadByForeignKeyByCacheIfEnabled(
Class<T> clazz, String foreignKey, DateTime now) {
return loadByForeignKeyHelper(
clazz, foreignKey, now, RegistryConfig.isEppResourceCachingEnabled());
tm(), clazz, foreignKey, now, RegistryConfig.isEppResourceCachingEnabled());
}
/**
* Loads the last created version of an {@link EppResource} from the replica database by foreign
* key, using a cache.
*
* <p>This method ignores the config setting for caching, and is reserved for use cases that can
* tolerate slightly stale data.
*/
public static <T extends EppResource> Optional<T> loadByForeignKeyByCache(
Class<T> clazz, String foreignKey, DateTime now) {
return loadByForeignKeyHelper(replicaTm(), clazz, foreignKey, now, true);
}
private static <T extends EppResource> Optional<T> loadByForeignKeyHelper(
Class<T> clazz, String foreignKey, DateTime now, boolean useCache) {
TransactionManager txnManager,
Class<T> clazz,
String foreignKey,
DateTime now,
boolean useCache) {
checkArgument(
ForeignKeyedEppResource.class.isAssignableFrom(clazz),
"loadByForeignKey may only be called for foreign keyed EPP resources");
VKey<T> key =
useCache
? ForeignKeyUtils.loadCached(clazz, ImmutableList.of(foreignKey), now).get(foreignKey)
? ForeignKeyUtils.loadByCache(clazz, ImmutableList.of(foreignKey), now).get(foreignKey)
: ForeignKeyUtils.load(clazz, foreignKey, now);
// The returned key is null if the resource is hard deleted or soft deleted by the given time.
if (key == null) {
@@ -155,10 +173,10 @@ public final class EppResourceUtils {
}
T resource =
useCache
? EppResource.loadCached(key)
? EppResource.loadByCache(key)
// This transaction is buried very deeply inside many outer nested calls, hence merits
// the use of reTransact() for now pending a substantial refactoring.
: tm().reTransact(() -> tm().loadByKeyIfPresent(key).orElse(null));
: txnManager.reTransact(() -> txnManager.loadByKeyIfPresent(key).orElse(null));
if (resource == null || isAtOrAfter(now, resource.getDeletionTime())) {
return Optional.empty();
}

View File

@@ -204,11 +204,25 @@ public final class ForeignKeyUtils {
* <p>Don't use the cached version of this method unless you really need it for performance
* reasons, and are OK with the trade-offs in loss of transactional consistency.
*/
public static <E extends EppResource> ImmutableMap<String, VKey<E>> loadCached(
public static <E extends EppResource> ImmutableMap<String, VKey<E>> loadByCacheIfEnabled(
Class<E> clazz, Collection<String> foreignKeys, final DateTime now) {
if (!RegistryConfig.isEppResourceCachingEnabled()) {
return load(clazz, foreignKeys, now);
}
return loadByCache(clazz, foreignKeys, now);
}
/**
* Load a list of {@link VKey} to {@link EppResource} instances by class and foreign key strings
* that are active at or after the specified moment in time, using the cache.
*
* <p>The returned map will omit any keys for which the {@link EppResource} doesn't exist or has
* been soft-deleted.
*
* <p>This method is reserved for use cases that can tolerate slightly stale data.
*/
public static <E extends EppResource> ImmutableMap<String, VKey<E>> loadByCache(
Class<E> clazz, Collection<String> foreignKeys, final DateTime now) {
return foreignKeyCache
.getAll(foreignKeys.stream().map(fk -> VKey.create(clazz, fk)).collect(toImmutableList()))
.entrySet()

View File

@@ -0,0 +1,150 @@
// Copyright 2025 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.model.console;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import google.registry.model.Buildable;
import google.registry.model.CreateAutoTimestamp;
import google.registry.model.ImmutableObject;
import google.registry.persistence.WithVKey;
import jakarta.persistence.AttributeOverride;
import jakarta.persistence.AttributeOverrides;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.Id;
import java.util.Optional;
import java.util.UUID;
import org.joda.time.DateTime;
/**
* Represents a password reset request of some type.
*
* <p>Password reset requests must be performed within an hour of the time that they were requested,
* as well as requiring that the requester and the fulfiller have the proper respective permissions.
*/
@Entity
@WithVKey(String.class)
public class PasswordResetRequest extends ImmutableObject implements Buildable {
public enum Type {
EPP,
REGISTRY_LOCK
}
@Id private String verificationCode;
@Column(nullable = false)
@Enumerated(EnumType.STRING)
Type type;
@AttributeOverrides({
@AttributeOverride(
name = "creationTime",
column = @Column(name = "requestTime", nullable = false))
})
CreateAutoTimestamp requestTime = CreateAutoTimestamp.create(null);
@Column(nullable = false)
String requester;
@Column DateTime fulfillmentTime;
@Column(nullable = false)
String destinationEmail;
@Column(nullable = false)
String registrarId;
public String getVerificationCode() {
return verificationCode;
}
public Type getType() {
return type;
}
public DateTime getRequestTime() {
return requestTime.getTimestamp();
}
public String getRequester() {
return requester;
}
public Optional<DateTime> getFulfillmentTime() {
return Optional.ofNullable(fulfillmentTime);
}
public String getDestinationEmail() {
return destinationEmail;
}
public String getRegistrarId() {
return registrarId;
}
@Override
public Builder asBuilder() {
return new Builder(clone(this));
}
/** Builder for constructing immutable {@link PasswordResetRequest} objects. */
public static class Builder extends Buildable.Builder<PasswordResetRequest> {
public Builder() {}
private Builder(PasswordResetRequest instance) {
super(instance);
}
@Override
public PasswordResetRequest build() {
checkArgumentNotNull(getInstance().type, "Type must be specified");
checkArgumentNotNull(getInstance().requester, "Requester must be specified");
checkArgumentNotNull(getInstance().destinationEmail, "Destination email must be specified");
checkArgumentNotNull(getInstance().registrarId, "Registrar ID must be specified");
getInstance().verificationCode = UUID.randomUUID().toString();
return super.build();
}
public Builder setType(Type type) {
getInstance().type = type;
return this;
}
public Builder setRequester(String requester) {
getInstance().requester = requester;
return this;
}
public Builder setDestinationEmail(String destinationEmail) {
getInstance().destinationEmail = destinationEmail;
return this;
}
public Builder setRegistrarId(String registrarId) {
getInstance().registrarId = registrarId;
return this;
}
public Builder setFulfillmentTime(DateTime fulfillmentTime) {
getInstance().fulfillmentTime = fulfillmentTime;
return this;
}
}
}

View File

@@ -441,7 +441,8 @@ public class DomainCommand {
private static <T extends EppResource> ImmutableMap<String, VKey<T>> loadByForeignKeysCached(
final Set<String> foreignKeys, final Class<T> clazz, final DateTime now)
throws InvalidReferencesException {
ImmutableMap<String, VKey<T>> fks = ForeignKeyUtils.loadCached(clazz, foreignKeys, now);
ImmutableMap<String, VKey<T>> fks =
ForeignKeyUtils.loadByCacheIfEnabled(clazz, foreignKeys, now);
if (!fks.keySet().equals(foreignKeys)) {
throw new InvalidReferencesException(
clazz, ImmutableSet.copyOf(difference(foreignKeys, fks.keySet())));

View File

@@ -27,6 +27,7 @@ import static com.google.common.io.BaseEncoding.base64;
import static google.registry.config.RegistryConfig.getDefaultRegistrarWhoisServer;
import static google.registry.model.CacheUtils.memoizeWithShortExpiration;
import static google.registry.model.tld.Tlds.assertTldsExist;
import static google.registry.persistence.transaction.TransactionManagerFactory.replicaTm;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
import static google.registry.util.CollectionUtils.nullToEmptyImmutableSortedCopy;
@@ -62,6 +63,7 @@ import google.registry.model.tld.Tld.TldType;
import google.registry.persistence.VKey;
import google.registry.persistence.converter.CidrBlockListUserType;
import google.registry.persistence.converter.CurrencyToStringMapUserType;
import google.registry.persistence.transaction.TransactionManager;
import google.registry.util.CidrAddressBlock;
import google.registry.util.PasswordUtils;
import jakarta.mail.internet.AddressException;
@@ -576,7 +578,20 @@ public class Registrar extends UpdateAutoTimestampEntity implements Buildable, J
* address.
*/
public ImmutableSortedSet<RegistrarPoc> getContacts() {
return getContactPocs().stream()
return getContactPocs(tm()).stream()
.filter(Objects::nonNull)
.collect(toImmutableSortedSet(CONTACT_EMAIL_COMPARATOR));
}
/**
* Returns a list of all {@link RegistrarPoc} objects for this registrar sorted by their email
* address.
*
* <p>This method queries the replica database. It is reserved for use cases that can tolerate
* slightly stale data.
*/
public ImmutableSortedSet<RegistrarPoc> getContactsFromReplica() {
return getContactPocs(replicaTm()).stream()
.filter(Objects::nonNull)
.collect(toImmutableSortedSet(CONTACT_EMAIL_COMPARATOR));
}
@@ -586,7 +601,7 @@ public class Registrar extends UpdateAutoTimestampEntity implements Buildable, J
* their email address.
*/
public ImmutableSortedSet<RegistrarPoc> getContactsOfType(final RegistrarPoc.Type type) {
return getContactPocs().stream()
return getContactPocs(tm()).stream()
.filter(Objects::nonNull)
.filter((@Nullable RegistrarPoc contact) -> contact.getTypes().contains(type))
.collect(toImmutableSortedSet(CONTACT_EMAIL_COMPARATOR));
@@ -600,13 +615,8 @@ public class Registrar extends UpdateAutoTimestampEntity implements Buildable, J
return getContacts().stream().filter(RegistrarPoc::getVisibleInDomainWhoisAsAbuse).findFirst();
}
private ImmutableSet<RegistrarPoc> getContactPocs() {
return tm().transact(
() ->
tm().query("FROM RegistrarPoc WHERE registrarId = :registrarId", RegistrarPoc.class)
.setParameter("registrarId", registrarId)
.getResultStream()
.collect(toImmutableSet()));
private ImmutableList<RegistrarPoc> getContactPocs(TransactionManager txnManager) {
return txnManager.transact(() -> RegistrarPoc.loadForRegistrar(registrarId));
}
@Override

View File

@@ -27,6 +27,7 @@ import static google.registry.util.PasswordUtils.hashPassword;
import static java.util.stream.Collectors.joining;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.gson.annotations.Expose;
@@ -36,6 +37,7 @@ import google.registry.model.JsonMapBuilder;
import google.registry.model.Jsonifiable;
import google.registry.model.UnsafeSerializable;
import google.registry.persistence.VKey;
import google.registry.persistence.transaction.QueryComposer;
import google.registry.util.PasswordUtils;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
@@ -93,6 +95,10 @@ public class RegistrarPoc extends ImmutableObject implements Jsonifiable, Unsafe
}
}
@Expose
@Column(insertable = false, updatable = false)
protected Long id;
/** The name of the contact. */
@Expose String name;
@@ -179,6 +185,10 @@ public class RegistrarPoc extends ImmutableObject implements Jsonifiable, Unsafe
tm().putAll(contacts);
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
@@ -295,6 +305,7 @@ public class RegistrarPoc extends ImmutableObject implements Jsonifiable, Unsafe
.put("visibleInDomainWhoisAsAbuse", visibleInDomainWhoisAsAbuse)
.put("allowedToSetRegistryLockPassword", allowedToSetRegistryLockPassword)
.put("registryLockAllowed", isRegistryLockAllowed())
.put("id", getId())
.build();
}
@@ -423,6 +434,12 @@ public class RegistrarPoc extends ImmutableObject implements Jsonifiable, Unsafe
}
}
public static ImmutableList<RegistrarPoc> loadForRegistrar(String registrarId) {
return tm().createQueryComposer(RegistrarPoc.class)
.where("registrarId", QueryComposer.Comparator.EQ, registrarId)
.list();
}
/** Class to represent the composite primary key for {@link RegistrarPoc} entity. */
@VisibleForTesting
public static class RegistrarPocId extends ImmutableObject implements Serializable {

View File

@@ -336,7 +336,7 @@ abstract class AbstractJsonableObject implements Jsonable {
// According to RFC 9083 section 3, the syntax of dates and times is defined in RFC3339.
//
// According to RFC3339, we should use ISO8601, which is what DateTime.toString does!
return new JsonPrimitive(((DateTime) object).toString());
return new JsonPrimitive(object.toString());
}
if (object == null) {
return JsonNull.INSTANCE;

View File

@@ -24,10 +24,14 @@ 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.collect.Streams;
import com.google.common.flogger.FluentLogger;
import com.google.common.net.MediaType;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import google.registry.config.RegistryConfig.Config;
import google.registry.model.EppResource;
import google.registry.model.registrar.Registrar;
@@ -41,6 +45,7 @@ import google.registry.request.HttpException;
import google.registry.request.Parameter;
import google.registry.request.RequestMethod;
import google.registry.request.RequestPath;
import google.registry.request.RequestUrl;
import google.registry.request.Response;
import google.registry.util.Clock;
import jakarta.inject.Inject;
@@ -75,6 +80,7 @@ public abstract class RdapActionBase implements Runnable {
@Inject Response response;
@Inject @RequestMethod Action.Method requestMethod;
@Inject @RequestPath String requestPath;
@Inject @RequestUrl String requestUrl;
@Inject RdapAuthorization rdapAuthorization;
@Inject RdapJsonFormatter rdapJsonFormatter;
@Inject @Parameter("includeDeleted") Optional<Boolean> includeDeletedParam;
@@ -198,7 +204,9 @@ public abstract class RdapActionBase implements Runnable {
TopLevelReplyObject topLevelObject =
TopLevelReplyObject.create(replyObject, rdapJsonFormatter.createTosNotice());
Gson gson = formatOutputParam.orElse(false) ? FORMATTED_OUTPUT_GSON : GSON;
response.setPayload(gson.toJson(topLevelObject.toJson()));
JsonObject jsonResult = topLevelObject.toJson();
addLinkValuesRecursively(jsonResult);
response.setPayload(gson.toJson(jsonResult));
}
/**
@@ -264,4 +272,34 @@ public abstract class RdapActionBase implements Runnable {
return rdapJsonFormatter.getRequestTime();
}
/**
* Adds a request-referencing "value" to each link object.
*
* <p>This is the "context URI" as described in RFC 8288. Basically, this contains a reference to
* the request URL that generated this RDAP response.
*
* <p>This is required per the RDAP February 2024 response profile sections 2.6.3 and 2.10, and
* the technical implementation guide sections 3.2 and 3.3.2.
*
* <p>We must do this here (instead of where the links are generated) because many of the links
* (e.g. terms of service) are static constants, and thus cannot by default know what the request
* URL was.
*/
private void addLinkValuesRecursively(JsonElement jsonElement) {
if (jsonElement instanceof JsonArray jsonArray) {
jsonArray.forEach(this::addLinkValuesRecursively);
} else if (jsonElement instanceof JsonObject jsonObject) {
if (jsonObject.get("links") instanceof JsonArray linksArray) {
addLinkValues(linksArray);
}
jsonObject.entrySet().forEach(entry -> addLinkValuesRecursively(entry.getValue()));
}
}
private void addLinkValues(JsonArray linksArray) {
Streams.stream(linksArray)
.map(JsonElement::getAsJsonObject)
.filter(o -> !o.has("value"))
.forEach(o -> o.addProperty("value", requestUrl));
}
}

View File

@@ -15,7 +15,7 @@
package google.registry.rdap;
import static google.registry.flows.domain.DomainFlowUtils.validateDomainName;
import static google.registry.model.EppResourceUtils.loadByForeignKeyCached;
import static google.registry.model.EppResourceUtils.loadByForeignKeyByCache;
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;
@@ -65,7 +65,7 @@ public class RdapDomainAction extends RdapActionBase {
}
// The query string is not used; the RDAP syntax is /rdap/domain/mydomain.com.
Optional<Domain> domain =
loadByForeignKeyCached(
loadByForeignKeyByCache(
Domain.class,
pathSearchString,
shouldIncludeDeleted() ? START_OF_TIME : rdapJsonFormatter.getRequestTime());

View File

@@ -15,7 +15,7 @@
package google.registry.rdap;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static google.registry.model.EppResourceUtils.loadByForeignKeyCached;
import static google.registry.model.EppResourceUtils.loadByForeignKeyByCache;
import static google.registry.persistence.transaction.TransactionManagerFactory.replicaTm;
import static google.registry.request.Action.Method.GET;
import static google.registry.request.Action.Method.HEAD;
@@ -184,7 +184,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
private DomainSearchResponse searchByDomainNameWithoutWildcard(
final RdapSearchPattern partialStringQuery) {
Optional<Domain> domain =
loadByForeignKeyCached(
loadByForeignKeyByCache(
Domain.class, partialStringQuery.getInitialString(), getRequestTime());
return makeSearchResults(
shouldBeVisible(domain) ? ImmutableList.of(domain.get()) : ImmutableList.of());
@@ -339,7 +339,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
Optional<String> desiredRegistrar = getDesiredRegistrar();
if (desiredRegistrar.isPresent()) {
Optional<Host> host =
loadByForeignKeyCached(
loadByForeignKeyByCache(
Host.class,
partialStringQuery.getInitialString(),
shouldIncludeDeleted() ? START_OF_TIME : getRequestTime());
@@ -364,7 +364,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
// through the subordinate hosts. This is more efficient, and lets us permit wildcard searches
// with no initial string.
Domain domain =
loadByForeignKeyCached(
loadByForeignKeyByCache(
Domain.class,
partialStringQuery.getSuffix(),
shouldIncludeDeleted() ? START_OF_TIME : getRequestTime())
@@ -381,7 +381,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
if (partialStringQuery.matches(fqhn)) {
if (desiredRegistrar.isPresent()) {
Optional<Host> host =
loadByForeignKeyCached(
loadByForeignKeyByCache(
Host.class, fqhn, shouldIncludeDeleted() ? START_OF_TIME : getRequestTime());
if (host.isPresent()
&& desiredRegistrar

View File

@@ -44,7 +44,7 @@ public class RdapIcannStandardInformation {
+ " https://icann.org/epp")
.addLink(
Link.builder()
.setRel("alternate")
.setRel("glossary")
.setHref("https://icann.org/epp")
.setType("text/html")
.build())
@@ -57,7 +57,7 @@ public class RdapIcannStandardInformation {
.setDescription("URL of the ICANN RDDS Inaccuracy Complaint Form: https://icann.org/wicf")
.addLink(
Link.builder()
.setRel("alternate")
.setRel("help")
.setHref("https://icann.org/wicf")
.setType("text/html")
.build())

View File

@@ -271,7 +271,7 @@ public class RdapJsonFormatter {
URI htmlUri = htmlBaseURI.resolve(rdapTosStaticUrl);
noticeBuilder.addLink(
Link.builder()
.setRel("alternate")
.setRel("terms-of-service")
.setHref(htmlUri.toString())
.setType("text/html")
.build());
@@ -740,7 +740,7 @@ public class RdapJsonFormatter {
//
if (outputDataType != OutputDataType.SUMMARY) {
ImmutableList<RdapContactEntity> registrarContacts =
registrar.getContacts().stream()
registrar.getContactsFromReplica().stream()
.map(RdapJsonFormatter::makeRdapJsonForRegistrarContact)
.filter(Optional::isPresent)
.map(Optional::get)

View File

@@ -15,7 +15,7 @@
package google.registry.rdap;
import static google.registry.flows.host.HostFlowUtils.validateHostName;
import static google.registry.model.EppResourceUtils.loadByForeignKeyCached;
import static google.registry.model.EppResourceUtils.loadByForeignKeyByCache;
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;
@@ -63,7 +63,7 @@ public class RdapNameserverAction extends RdapActionBase {
// If there are no undeleted nameservers with the given name, the foreign key should point to
// the most recently deleted one.
Optional<Host> host =
loadByForeignKeyCached(
loadByForeignKeyByCache(
Host.class,
pathSearchString,
shouldIncludeDeleted() ? START_OF_TIME : getRequestTime());

View File

@@ -14,7 +14,7 @@
package google.registry.rdap;
import static google.registry.model.EppResourceUtils.loadByForeignKeyCached;
import static google.registry.model.EppResourceUtils.loadByForeignKeyByCache;
import static google.registry.persistence.transaction.TransactionManagerFactory.replicaTm;
import static google.registry.request.Action.Method.GET;
import static google.registry.request.Action.Method.HEAD;
@@ -159,7 +159,8 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
.setIncompletenessWarningType(IncompletenessWarningType.COMPLETE);
Optional<Host> host =
loadByForeignKeyCached(Host.class, partialStringQuery.getInitialString(), getRequestTime());
loadByForeignKeyByCache(
Host.class, partialStringQuery.getInitialString(), getRequestTime());
metricInformationBuilder.setNumHostsRetrieved(host.isPresent() ? 1 : 0);
@@ -175,7 +176,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
private NameserverSearchResponse searchByNameUsingSuperordinateDomain(
RdapSearchPattern partialStringQuery) {
Optional<Domain> domain =
loadByForeignKeyCached(Domain.class, partialStringQuery.getSuffix(), getRequestTime());
loadByForeignKeyByCache(Domain.class, partialStringQuery.getSuffix(), getRequestTime());
if (domain.isEmpty()) {
// Don't allow wildcards with suffixes which are not domains we manage. That would risk a
// table scan in many easily foreseeable cases. The user might ask for ns*.zombo.com,
@@ -193,7 +194,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
// We can't just check that the host name starts with the initial query string, because
// then the query ns.exam*.example.com would match against nameserver ns.example.com.
if (partialStringQuery.matches(fqhn)) {
Optional<Host> host = loadByForeignKeyCached(Host.class, fqhn, getRequestTime());
Optional<Host> host = loadByForeignKeyByCache(Host.class, fqhn, getRequestTime());
if (shouldBeVisible(host)) {
hostList.add(host.get());
if (hostList.size() > rdapResultSetMaxSize) {

View File

@@ -31,7 +31,6 @@ import google.registry.request.HttpException.BadRequestException;
import google.registry.request.HttpException.UnprocessableEntityException;
import google.registry.request.Parameter;
import google.registry.request.ParameterMap;
import google.registry.request.RequestUrl;
import jakarta.inject.Inject;
import jakarta.persistence.criteria.CriteriaBuilder;
import java.io.UnsupportedEncodingException;
@@ -54,7 +53,6 @@ public abstract class RdapSearchActionBase extends RdapActionBase {
private static final int RESULT_SET_SIZE_SCALING_FACTOR = 30;
@Inject @RequestUrl String requestUrl;
@Inject @ParameterMap ImmutableListMultimap<String, String> parameterMap;
@Inject @Parameter("cursor") Optional<String> cursorTokenParam;
@Inject @Parameter("registrar") Optional<String> registrarParam;

View File

@@ -16,7 +16,7 @@ package google.registry.tools;
import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_ACTIONS;
import static google.registry.model.EppResourceUtils.loadByForeignKeyCached;
import static google.registry.model.EppResourceUtils.loadByForeignKeyByCacheIfEnabled;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.tools.LockOrUnlockDomainCommand.REGISTRY_LOCK_STATUSES;
@@ -326,7 +326,7 @@ public final class DomainLockUtils {
private Domain getDomain(String domainName, String registrarId, DateTime now) {
Domain domain =
loadByForeignKeyCached(Domain.class, domainName, now)
loadByForeignKeyByCacheIfEnabled(Domain.class, domainName, now)
.orElseThrow(() -> new IllegalArgumentException("Domain doesn't exist"));
// The user must have specified either the correct registrar ID or the admin registrar ID
checkArgument(

View File

@@ -251,11 +251,12 @@ final class UniformRapidSuspensionCommand extends MutatingEppToolCommand {
if (undo) {
return "";
}
StringBuilder undoBuilder = new StringBuilder("UNDO COMMAND:\n\n)")
.append("nomulus -e ")
.append(RegistryToolEnvironment.get())
.append(" uniform_rapid_suspension --undo --domain_name ")
.append(domainName);
StringBuilder undoBuilder =
new StringBuilder("UNDO COMMAND:\n\n")
.append("nomulus -e ")
.append(RegistryToolEnvironment.get())
.append(" uniform_rapid_suspension --undo --domain_name ")
.append(domainName);
if (!existingNameservers.isEmpty()) {
undoBuilder.append(" --hosts ").append(Joiner.on(',').join(existingNameservers));
}

View File

@@ -55,7 +55,7 @@ public class ConsoleDomainGetAction extends ConsoleApiAction {
Optional<Domain> possibleDomain =
tm().transact(
() ->
EppResourceUtils.loadByForeignKeyCached(
EppResourceUtils.loadByForeignKeyByCacheIfEnabled(
Domain.class, paramDomain, tm().getTransactionTime()));
if (possibleDomain.isEmpty()) {
consoleApiParams.response().setStatus(SC_NOT_FOUND);

View File

@@ -19,7 +19,6 @@ import static google.registry.request.RequestParameters.extractOptionalIntParame
import static google.registry.request.RequestParameters.extractOptionalParameter;
import static google.registry.request.RequestParameters.extractRequiredParameter;
import com.google.common.collect.ImmutableSet;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import dagger.Module;
@@ -192,10 +191,10 @@ public final class ConsoleModule {
}
@Provides
@Parameter("contacts")
public static Optional<ImmutableSet<RegistrarPoc>> provideContacts(
@Parameter("contact")
public static Optional<RegistrarPoc> provideContacts(
Gson gson, @OptionalJsonPayload Optional<JsonElement> payload) {
return payload.map(s -> ImmutableSet.copyOf(gson.fromJson(s, RegistrarPoc[].class)));
return payload.map(s -> gson.fromJson(s, RegistrarPoc.class));
}
@Provides

View File

@@ -15,12 +15,13 @@
package google.registry.ui.server.console.settings;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.Sets.difference;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.request.Action.Method.DELETE;
import static google.registry.request.Action.Method.GET;
import static google.registry.request.Action.Method.POST;
import static google.registry.request.Action.Method.PUT;
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
import com.google.common.collect.HashMultimap;
@@ -33,66 +34,122 @@ import google.registry.model.console.User;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.model.registrar.RegistrarPoc.Type;
import google.registry.persistence.transaction.QueryComposer.Comparator;
import google.registry.request.Action;
import google.registry.request.Action.GaeService;
import google.registry.request.Action.GkeService;
import google.registry.request.Parameter;
import google.registry.request.auth.Auth;
import google.registry.ui.forms.FormException;
import google.registry.ui.server.RegistrarFormFields;
import google.registry.ui.server.console.ConsoleApiAction;
import google.registry.ui.server.console.ConsoleApiParams;
import jakarta.inject.Inject;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiFunction;
@Action(
service = GaeService.DEFAULT,
gkeService = GkeService.CONSOLE,
path = ContactAction.PATH,
method = {GET, POST},
method = {GET, POST, DELETE, PUT},
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
public class ContactAction extends ConsoleApiAction {
static final String PATH = "/console-api/settings/contacts";
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private final Optional<ImmutableSet<RegistrarPoc>> contacts;
private final Optional<RegistrarPoc> contact;
private final String registrarId;
@Inject
public ContactAction(
ConsoleApiParams consoleApiParams,
@Parameter("registrarId") String registrarId,
@Parameter("contacts") Optional<ImmutableSet<RegistrarPoc>> contacts) {
@Parameter("contact") Optional<RegistrarPoc> contact) {
super(consoleApiParams);
this.registrarId = registrarId;
this.contacts = contacts;
this.contact = contact;
}
@Override
protected void getHandler(User user) {
checkPermission(user, registrarId, ConsolePermission.VIEW_REGISTRAR_DETAILS);
ImmutableList<RegistrarPoc> am =
tm().transact(
() ->
tm()
.createQueryComposer(RegistrarPoc.class)
.where("registrarId", Comparator.EQ, registrarId)
.stream()
.filter(r -> !r.getTypes().isEmpty())
.collect(toImmutableList()));
ImmutableList<RegistrarPoc> contacts =
tm().transact(() -> RegistrarPoc.loadForRegistrar(registrarId));
consoleApiParams.response().setStatus(SC_OK);
consoleApiParams.response().setPayload(consoleApiParams.gson().toJson(am));
consoleApiParams.response().setPayload(consoleApiParams.gson().toJson(contacts));
}
@Override
protected void deleteHandler(User user) {
updateContacts(
user,
(registrar, oldContacts) ->
oldContacts.stream()
.filter(
oldContact ->
!oldContact.getEmailAddress().equals(contact.get().getEmailAddress()))
.collect(toImmutableSet()));
}
@Override
protected void postHandler(User user) {
updateContacts(
user,
(registrar, oldContacts) -> {
RegistrarPoc newContact = contact.get();
return ImmutableSet.<RegistrarPoc>builder()
.addAll(oldContacts)
.add(
new RegistrarPoc()
.asBuilder()
.setTypes(newContact.getTypes())
.setVisibleInWhoisAsTech(newContact.getVisibleInWhoisAsTech())
.setVisibleInWhoisAsAdmin(newContact.getVisibleInWhoisAsAdmin())
.setVisibleInDomainWhoisAsAbuse(newContact.getVisibleInDomainWhoisAsAbuse())
.setFaxNumber(newContact.getFaxNumber())
.setName(newContact.getName())
.setEmailAddress(newContact.getEmailAddress())
.setPhoneNumber(newContact.getPhoneNumber())
.setRegistrar(registrar)
.build())
.build();
});
}
@Override
protected void putHandler(User user) {
updateContacts(
user,
(registrar, oldContacts) -> {
RegistrarPoc updatedContact = contact.get();
return oldContacts.stream()
.map(
oldContact ->
oldContact.getId().equals(updatedContact.getId())
? oldContact
.asBuilder()
.setTypes(updatedContact.getTypes())
.setVisibleInWhoisAsTech(updatedContact.getVisibleInWhoisAsTech())
.setVisibleInWhoisAsAdmin(updatedContact.getVisibleInWhoisAsAdmin())
.setVisibleInDomainWhoisAsAbuse(
updatedContact.getVisibleInDomainWhoisAsAbuse())
.setFaxNumber(updatedContact.getFaxNumber())
.setName(updatedContact.getName())
.setEmailAddress(updatedContact.getEmailAddress())
.setPhoneNumber(updatedContact.getPhoneNumber())
.build()
: oldContact)
.collect(toImmutableSet());
});
}
private void updateContacts(
User user,
BiFunction<Registrar, ImmutableSet<RegistrarPoc>, ImmutableSet<RegistrarPoc>>
contactsUpdater) {
checkPermission(user, registrarId, ConsolePermission.EDIT_REGISTRAR_DETAILS);
checkArgument(contacts.isPresent(), "Contacts parameter is not present");
checkArgument(contact.isPresent(), "Contact parameter is not present");
Registrar registrar =
Registrar.loadByRegistrarId(registrarId)
.orElseThrow(
@@ -101,20 +158,10 @@ public class ContactAction extends ConsoleApiAction {
String.format("Unknown registrar %s", registrarId)));
ImmutableSet<RegistrarPoc> oldContacts = registrar.getContacts();
ImmutableSet<RegistrarPoc> updatedContacts =
RegistrarFormFields.getRegistrarContactBuilders(
oldContacts,
Collections.singletonMap(
"contacts",
contacts.get().stream()
.map(RegistrarPoc::toJsonMap)
.collect(toImmutableList())))
.stream()
.map(builder -> builder.setRegistrar(registrar).build())
.collect(toImmutableSet());
ImmutableSet<RegistrarPoc> newContacts = contactsUpdater.apply(registrar, oldContacts);
try {
checkContactRequirements(oldContacts, updatedContacts);
checkContactRequirements(oldContacts, newContacts);
} catch (FormException e) {
logger.atWarning().withCause(e).log(
"Error processing contacts post request for registrar: %s", registrarId);
@@ -123,14 +170,13 @@ public class ContactAction extends ConsoleApiAction {
tm().transact(
() -> {
RegistrarPoc.updateContacts(registrar, updatedContacts);
RegistrarPoc.updateContacts(registrar, newContacts);
Registrar updatedRegistrar =
registrar.asBuilder().setContactsRequireSyncing(true).build();
tm().put(updatedRegistrar);
sendExternalUpdatesIfNecessary(
EmailInfo.create(registrar, updatedRegistrar, oldContacts, updatedContacts));
EmailInfo.create(registrar, updatedRegistrar, oldContacts, newContacts));
});
consoleApiParams.response().setStatus(SC_OK);
}
@@ -169,6 +215,7 @@ public class ContactAction extends ConsoleApiAction {
throw new ContactRequirementException(t);
}
}
enforcePrimaryContactRestrictions(oldContactsByType, newContactsByType);
ensurePhoneNumberNotRemovedForContactTypes(oldContactsByType, newContactsByType, Type.TECH);
Optional<RegistrarPoc> domainWhoisAbuseContact =

View File

@@ -17,7 +17,7 @@ package google.registry.whois;
import static com.google.common.base.Preconditions.checkNotNull;
import static google.registry.flows.domain.DomainFlowUtils.isBlockedByBsa;
import static google.registry.model.EppResourceUtils.loadByForeignKey;
import static google.registry.model.EppResourceUtils.loadByForeignKeyCached;
import static google.registry.model.EppResourceUtils.loadByForeignKeyByCache;
import static google.registry.model.tld.Tlds.findTldForName;
import static google.registry.model.tld.Tlds.getTlds;
import static google.registry.persistence.transaction.TransactionManagerFactory.replicaTm;
@@ -94,7 +94,7 @@ public class DomainLookupCommand implements WhoisCommand {
private Optional<WhoisResponse> getResponse(InternetDomainName domainName, DateTime now) {
Optional<Domain> domainResource =
cached
? loadByForeignKeyCached(Domain.class, domainName.toString(), now)
? loadByForeignKeyByCache(Domain.class, domainName.toString(), now)
: loadByForeignKey(Domain.class, domainName.toString(), now);
return domainResource.map(
domain -> new DomainWhoisResponse(domain, fullOutput, whoisRedactedEmailText, now));

View File

@@ -81,7 +81,7 @@ final class DomainWhoisResponse extends WhoisResponseImpl {
domain.getCurrentSponsorRegistrarId());
Registrar registrar = registrarOptional.get();
Optional<RegistrarPoc> abuseContact =
registrar.getContacts().stream()
registrar.getContactsFromReplica().stream()
.filter(RegistrarPoc::getVisibleInDomainWhoisAsAbuse)
.findFirst();
return WhoisResponseResults.create(
@@ -154,7 +154,7 @@ final class DomainWhoisResponse extends WhoisResponseImpl {
// If we refer to a contact that doesn't exist, that's a bug. It means referential integrity
// has somehow been broken. We skip the rest of this contact, but log it to hopefully bring it
// someone's attention.
Contact contact1 = EppResource.loadCached(contact.get());
Contact contact1 = EppResource.loadByCache(contact.get());
if (contact1 == null) {
logger.atSevere().log(
"(BUG) Broken reference found from domain %s to contact %s.",

View File

@@ -16,7 +16,7 @@ package google.registry.whois;
import static com.google.common.base.Preconditions.checkNotNull;
import static google.registry.model.EppResourceUtils.loadByForeignKey;
import static google.registry.model.EppResourceUtils.loadByForeignKeyCached;
import static google.registry.model.EppResourceUtils.loadByForeignKeyByCache;
import static google.registry.model.tld.Tlds.findTldForName;
import static google.registry.model.tld.Tlds.getTlds;
import static jakarta.servlet.http.HttpServletResponse.SC_NOT_FOUND;
@@ -57,7 +57,7 @@ public class NameserverLookupByHostCommand implements WhoisCommand {
private Optional<WhoisResponse> getResponse(InternetDomainName hostName, DateTime now) {
Optional<Host> host =
cached
? loadByForeignKeyCached(Host.class, hostName.toString(), now)
? loadByForeignKeyByCache(Host.class, hostName.toString(), now)
: loadByForeignKey(Host.class, hostName.toString(), now);
return host.map(h -> new NameserverWhoisResponse(h, now));
}

View File

@@ -44,7 +44,7 @@ class RegistrarWhoisResponse extends WhoisResponseImpl {
@Override
public WhoisResponseResults getResponse(boolean preferUnicode, String disclaimer) {
Set<RegistrarPoc> contacts = registrar.getContacts();
Set<RegistrarPoc> contacts = registrar.getContactsFromReplica();
String plaintext =
new RegistrarEmitter()
.emitField("Registrar", registrar.getRegistrarName())

View File

@@ -47,13 +47,14 @@
<class>google.registry.model.billing.BillingRecurrence</class>
<class>google.registry.model.common.Cursor</class>
<class>google.registry.model.common.DnsRefreshRequest</class>
<class>google.registry.model.common.FeatureFlag</class>
<class>google.registry.model.console.ConsoleUpdateHistory</class>
<class>google.registry.model.console.PasswordResetRequest</class>
<class>google.registry.model.console.User</class>
<class>google.registry.model.contact.ContactHistory</class>
<class>google.registry.model.contact.Contact</class>
<class>google.registry.model.domain.Domain</class>
<class>google.registry.model.domain.DomainHistory</class>
<class>google.registry.model.common.FeatureFlag</class>
<class>google.registry.model.domain.GracePeriod</class>
<class>google.registry.model.domain.GracePeriod$GracePeriodHistory</class>
<class>google.registry.model.domain.secdns.DomainDsData</class>

View File

@@ -36,27 +36,27 @@ public class EppResourceTest extends EntityTestCase {
new TestCacheExtension.Builder().withEppResourceCache(Duration.ofDays(1)).build();
@Test
void test_loadCached_ignoresContactChange() {
void test_loadByCacheIfEnabled_ignoresContactChange() {
Contact originalContact = persistActiveContact("contact123");
assertThat(EppResource.loadCached(ImmutableList.of(originalContact.createVKey())))
assertThat(EppResource.loadByCacheIfEnabled(ImmutableList.of(originalContact.createVKey())))
.containsExactly(originalContact.createVKey(), originalContact);
Contact modifiedContact =
persistResource(originalContact.asBuilder().setEmailAddress("different@fake.lol").build());
assertThat(EppResource.loadCached(ImmutableList.of(originalContact.createVKey())))
assertThat(EppResource.loadByCacheIfEnabled(ImmutableList.of(originalContact.createVKey())))
.containsExactly(originalContact.createVKey(), originalContact);
assertThat(loadByForeignKey(Contact.class, "contact123", fakeClock.nowUtc()))
.hasValue(modifiedContact);
}
@Test
void test_loadCached_ignoresHostChange() {
void test_loadByCacheIfEnabled_ignoresHostChange() {
Host originalHost = persistActiveHost("ns1.example.com");
assertThat(EppResource.loadCached(ImmutableList.of(originalHost.createVKey())))
assertThat(EppResource.loadByCacheIfEnabled(ImmutableList.of(originalHost.createVKey())))
.containsExactly(originalHost.createVKey(), originalHost);
Host modifiedHost =
persistResource(
originalHost.asBuilder().setLastTransferTime(fakeClock.nowUtc().minusDays(60)).build());
assertThat(EppResource.loadCached(ImmutableList.of(originalHost.createVKey())))
assertThat(EppResource.loadByCacheIfEnabled(ImmutableList.of(originalHost.createVKey())))
.containsExactly(originalHost.createVKey(), originalHost);
assertThat(loadByForeignKey(Host.class, "ns1.example.com", fakeClock.nowUtc()))
.hasValue(modifiedHost);

View File

@@ -121,7 +121,7 @@ class ForeignKeyUtilsTest {
fakeClock.advanceOneMilli();
Host newHost1 = persistActiveHost("ns1.example.com");
assertThat(
ForeignKeyUtils.loadCached(
ForeignKeyUtils.loadByCacheIfEnabled(
Host.class,
ImmutableList.of("ns1.example.com", "ns2.example.com", "ns3.example.com"),
fakeClock.nowUtc()))
@@ -134,7 +134,7 @@ class ForeignKeyUtilsTest {
Host host2 = persistActiveHost("ns2.example.com");
persistResource(host2.asBuilder().setDeletionTime(fakeClock.nowUtc().minusDays(1)).build());
assertThat(
ForeignKeyUtils.loadCached(
ForeignKeyUtils.loadByCacheIfEnabled(
Host.class,
ImmutableList.of("ns1.example.com", "ns2.example.com", "ns3.example.com"),
fakeClock.nowUtc()))
@@ -144,7 +144,7 @@ class ForeignKeyUtilsTest {
persistActiveHost("ns1.example.com");
// Even though a new host1 is now live, the cache still returns the VKey to the old one.
assertThat(
ForeignKeyUtils.loadCached(
ForeignKeyUtils.loadByCacheIfEnabled(
Host.class,
ImmutableList.of("ns1.example.com", "ns2.example.com", "ns3.example.com"),
fakeClock.nowUtc()))

View File

@@ -0,0 +1,65 @@
// Copyright 2025 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.model.console;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
import static google.registry.testing.DatabaseHelper.persistResource;
import static org.junit.Assert.assertThrows;
import google.registry.model.EntityTestCase;
import google.registry.persistence.VKey;
import google.registry.testing.DatabaseHelper;
import org.junit.jupiter.api.Test;
/** Tests for {@link PasswordResetRequest}. */
public class PasswordResetRequestTest extends EntityTestCase {
PasswordResetRequestTest() {
super(JpaEntityCoverageCheck.ENABLED);
}
@Test
void testSuccess_persistence() {
PasswordResetRequest request =
new PasswordResetRequest.Builder()
.setRequester("requestor@email.tld")
.setDestinationEmail("destination@email.tld")
.setType(PasswordResetRequest.Type.EPP)
.setRegistrarId("TheRegistrar")
.build();
String verificationCode = request.getVerificationCode();
assertThat(verificationCode).isNotEmpty();
persistResource(request);
PasswordResetRequest fromDatabase =
DatabaseHelper.loadByKey(VKey.create(PasswordResetRequest.class, verificationCode));
assertAboutImmutableObjects().that(fromDatabase).isEqualExceptFields(request, "requestTime");
assertThat(fromDatabase.getRequestTime()).isEqualTo(fakeClock.nowUtc());
}
@Test
void testFailure_nullFields() {
PasswordResetRequest.Builder builder = new PasswordResetRequest.Builder();
assertThrows(IllegalArgumentException.class, builder::build);
builder.setType(PasswordResetRequest.Type.EPP);
assertThrows(IllegalArgumentException.class, builder::build);
builder.setRequester("foobar@email.tld");
assertThrows(IllegalArgumentException.class, builder::build);
builder.setDestinationEmail("email@email.tld");
assertThrows(IllegalArgumentException.class, builder::build);
builder.setRegistrarId("TheRegistrar");
builder.build();
}
}

View File

@@ -44,6 +44,7 @@ import google.registry.model.registrar.Registrar.Type;
import google.registry.model.tld.Tld;
import google.registry.model.tld.Tld.TldType;
import google.registry.model.tld.Tlds;
import google.registry.testing.DatabaseHelper;
import google.registry.util.CidrAddressBlock;
import google.registry.util.SerializeUtils;
import java.math.BigDecimal;
@@ -340,6 +341,7 @@ class RegistrarTest extends EntityTestCase {
.setFaxNumber("+1.2125551213")
.setTypes(ImmutableSet.of(RegistrarPoc.Type.TECH, RegistrarPoc.Type.ABUSE))
.build());
abuseAdminContact = DatabaseHelper.loadByKey(abuseAdminContact.createVKey());
ImmutableSortedSet<RegistrarPoc> techContacts =
registrar.getContactsOfType(RegistrarPoc.Type.TECH);
assertThat(techContacts).containsExactly(newTechContact, newTechAbuseContact).inOrder();

View File

@@ -90,12 +90,6 @@ class RdapActionBaseTest extends RdapActionBaseTestCase<RdapActionBaseTest.RdapT
assertThat(response.getStatus()).isEqualTo(500);
}
@Test
void testValidName_works() {
assertThat(generateActualJson("no.thing")).isEqualTo(loadJsonFile("rdapjson_toplevel.json"));
assertThat(response.getStatus()).isEqualTo(200);
}
@Test
void testContentType_rdapjson_utf8() {
generateActualJson("no.thing");

View File

@@ -22,7 +22,12 @@ import static google.registry.request.Action.Method.GET;
import static google.registry.request.Action.Method.HEAD;
import static org.mockito.Mockito.mock;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import google.registry.model.console.User;
import google.registry.model.console.UserRoles;
import google.registry.persistence.transaction.JpaTestExtensions;
@@ -35,6 +40,7 @@ import google.registry.util.Idn;
import google.registry.util.TypeUtils;
import java.util.HashMap;
import java.util.Optional;
import javax.annotation.Nullable;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -43,6 +49,7 @@ import org.junit.jupiter.api.extension.RegisterExtension;
abstract class RdapActionBaseTestCase<A extends RdapActionBase> {
protected final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01TZ"));
static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
@RegisterExtension
final JpaIntegrationTestExtension jpa =
@@ -107,18 +114,13 @@ abstract class RdapActionBaseTestCase<A extends RdapActionBase> {
metricRole = ADMINISTRATOR;
}
JsonObject generateActualJson(String domainName) {
action.requestPath = actionPath + domainName;
action.requestMethod = GET;
action.run();
return RdapTestHelper.parseJsonObject(response.getPayload());
JsonObject generateActualJson(String name) {
return RdapTestHelper.parseJsonObject(runAction(name));
}
String generateHeadPayload(String domainName) {
action.requestPath = actionPath + domainName;
String generateHeadPayload(String name) {
action.requestMethod = HEAD;
action.run();
return response.getPayload();
return runAction(name);
}
JsonObject generateExpectedJsonError(String description, int code) {
@@ -138,16 +140,135 @@ abstract class RdapActionBaseTestCase<A extends RdapActionBase> {
"TITLE",
title,
"CODE",
String.valueOf(code));
String.valueOf(code),
"REQUEST_URL",
action.requestUrl);
}
static JsonFileBuilder jsonFileBuilder() {
return new JsonFileBuilder();
JsonFileBuilder jsonFileBuilder() {
return new JsonFileBuilder(action.requestUrl);
}
private String runAction(String name) {
action.requestPath = actionPath + name;
action.requestUrl = "https://example.tld" + actionPath + name;
action.run();
return response.getPayload();
}
JsonElement createTosNotice() {
return JsonParser.parseString(
"""
{
"title": "RDAP Terms of Service",
"description": [
"By querying our Domain Database, you are agreeing to comply with these terms so please read \
them carefully.",
"Any information provided is 'as is' without any guarantee of accuracy.",
"Please do not misuse the Domain Database. It is intended solely for query-based access.",
"Don't use the Domain Database to allow, enable, or otherwise support the transmission of mass \
unsolicited, commercial advertising or solicitations.",
"Don't access our Domain Database through the use of high volume, automated electronic \
processes that send queries or data to the systems of any ICANN-accredited registrar.",
"You may only use the information contained in the Domain Database for lawful purposes.",
"Do not compile, repackage, disseminate, or otherwise use the information contained in the \
Domain Database in its entirety, or in any substantial portion, without our prior written \
permission.",
"We may retain certain details about queries to our Domain Database for the purposes of \
detecting and preventing misuse.",
"We reserve the right to restrict or deny your access to the database if we suspect that you \
have failed to comply with these terms.",
"We reserve the right to modify this agreement at any time."
],
"links": [
{
"rel": "self",
"href": "https://example.tld/rdap/help/tos",
"type": "application/rdap+json",
"value": "%REQUEST_URL%"
},
{
"rel": "terms-of-service",
"href": "https://www.example.tld/about/rdap/tos.html",
"type": "text/html",
"value": "%REQUEST_URL%"
}
]
}
"""
.replaceAll("%REQUEST_URL%", action.requestUrl));
}
JsonObject addPermanentBoilerplateNotices(JsonObject jsonObject) {
if (!jsonObject.has("notices")) {
jsonObject.add("notices", new JsonArray());
}
JsonArray notices = jsonObject.getAsJsonArray("notices");
notices.add(createTosNotice());
notices.add(
JsonParser.parseString(
"""
{
"description": [
"This response conforms to the RDAP Operational Profile for gTLD Registries and Registrars \
version 1.0"
]
}
"""));
return jsonObject;
}
JsonObject addDomainBoilerplateNotices(JsonObject jsonObject) {
addPermanentBoilerplateNotices(jsonObject);
JsonArray notices = jsonObject.getAsJsonArray("notices");
notices.add(
JsonParser.parseString(
"""
{
"title": "Status Codes",
"description": [
"For more information on domain status codes, please visit https://icann.org/epp"
],
"links": [
{
"rel": "glossary",
"href": "https://icann.org/epp",
"type": "text/html",
"value": "%REQUEST_URL%"
}
]
}
"""
.replaceAll("%REQUEST_URL%", action.requestUrl)));
notices.add(
JsonParser.parseString(
"""
{
"title": "RDDS Inaccuracy Complaint Form",
"description": [
"URL of the ICANN RDDS Inaccuracy Complaint Form: https://icann.org/wicf"
],
"links": [
{
"rel": "help",
"href": "https://icann.org/wicf",
"type": "text/html",
"value": "%REQUEST_URL%"
}
]
}
"""
.replaceAll("%REQUEST_URL%", action.requestUrl)));
return jsonObject;
}
protected static final class JsonFileBuilder {
private final HashMap<String, String> substitutions = new HashMap<>();
private JsonFileBuilder(String requestUrl) {
substitutions.put("REQUEST_URL", requestUrl);
}
public JsonObject load(String filename) {
return RdapTestHelper.loadJsonFile(filename, substitutions);
}
@@ -158,6 +279,14 @@ abstract class RdapActionBaseTestCase<A extends RdapActionBase> {
return this;
}
public JsonFileBuilder putAll(String... keysAndValues) {
checkArgument(keysAndValues.length % 2 == 0);
for (int i = 0; i < keysAndValues.length; i += 2) {
put(keysAndValues[i], keysAndValues[i + 1]);
}
return this;
}
public JsonFileBuilder put(String key, int index, String value) {
return put(String.format("%s%d", key, index), value);
}
@@ -189,10 +318,38 @@ abstract class RdapActionBaseTestCase<A extends RdapActionBase> {
return putNext("REGISTRAR_FULL_NAME_", fullName);
}
JsonFileBuilder addFullRegistrar(
String handle, @Nullable String fullName, String status, @Nullable String address) {
if (fullName != null) {
putNext("REGISTRAR_FULLNAME_", fullName);
}
if (address != null) {
putNext("REGISTRAR_ADDRESS_", address);
}
return putNext("REGISTRAR_HANDLE_", handle, "STATUS_", status);
}
JsonFileBuilder addContact(String handle) {
return putNext("CONTACT_HANDLE_", handle);
}
JsonFileBuilder addFullContact(
String handle,
@Nullable String status,
@Nullable String fullName,
@Nullable String address) {
if (fullName != null) {
putNext("CONTACT_FULLNAME_", fullName);
}
if (address != null) {
putNext("CONTACT_ADDRESS_", address);
}
if (status != null) {
putNext("STATUS_", status);
}
return putNext("CONTACT_HANDLE_", handle);
}
JsonFileBuilder setNextQuery(String nextQuery) {
return put("NEXT_QUERY", nextQuery);
}

View File

@@ -59,9 +59,12 @@ final class RdapDataStructuresTest {
.setRel("myRel")
.setTitle("myTitle")
.setType("myType")
.setValue("myValue")
.build();
assertThat(link.toJson())
.isEqualTo(createJson("{'href':'myHref','rel':'myRel','title':'myTitle','type':'myType'}"));
.isEqualTo(
createJson(
"{'href':'myHref','rel':'myRel','title':'myTitle','type':'myType','value':'myValue'}"));
assertRestrictedNames(link, "links[]");
}

View File

@@ -230,16 +230,11 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
clock.nowUtc().minusMonths(6)));
}
private JsonObject addBoilerplate(JsonObject obj) {
RdapTestHelper.addDomainBoilerplateNotices(obj, "https://example.tld/rdap/");
return obj;
}
private void assertProperResponseForCatLol(String queryString, String expectedOutputFile) {
assertAboutJson()
.that(generateActualJson(queryString))
.isEqualTo(
addBoilerplate(
addDomainBoilerplateNotices(
jsonFileBuilder()
.addDomain("cat.lol", "C-LOL")
.addContact("4-ROID")
@@ -357,7 +352,7 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
assertAboutJson()
.that(generateActualJson("cat.みんな"))
.isEqualTo(
addBoilerplate(
addDomainBoilerplateNotices(
jsonFileBuilder()
.addDomain("cat.みんな", "1D-Q9JYB4C")
.addContact("19-ROID")
@@ -376,7 +371,7 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
assertAboutJson()
.that(generateActualJson("cat.%E3%81%BF%E3%82%93%E3%81%AA"))
.isEqualTo(
addBoilerplate(
addDomainBoilerplateNotices(
jsonFileBuilder()
.addDomain("cat.みんな", "1D-Q9JYB4C")
.addContact("19-ROID")
@@ -395,7 +390,7 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
assertAboutJson()
.that(generateActualJson("cat.xn--q9jyb4c"))
.isEqualTo(
addBoilerplate(
addDomainBoilerplateNotices(
jsonFileBuilder()
.addDomain("cat.みんな", "1D-Q9JYB4C")
.addContact("19-ROID")
@@ -414,7 +409,7 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
assertAboutJson()
.that(generateActualJson("cat.1.tld"))
.isEqualTo(
addBoilerplate(
addDomainBoilerplateNotices(
jsonFileBuilder()
.addDomain("cat.1.tld", "25-1_TLD")
.addContact("21-ROID")
@@ -473,7 +468,7 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
assertAboutJson()
.that(generateActualJson("dodo.lol"))
.isEqualTo(
addBoilerplate(
addDomainBoilerplateNotices(
jsonFileBuilder()
.addDomain("dodo.lol", "15-LOL")
.addContact("11-ROID")
@@ -493,7 +488,7 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
assertAboutJson()
.that(generateActualJson("dodo.lol"))
.isEqualTo(
addBoilerplate(
addDomainBoilerplateNotices(
jsonFileBuilder()
.addDomain("dodo.lol", "15-LOL")
.addContact("11-ROID")
@@ -512,7 +507,9 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
"addgraceperiod", "lol", clock.nowUtc(), clock.nowUtc().plusYears(1));
assertAboutJson()
.that(generateActualJson("addgraceperiod.lol"))
.isEqualTo(addBoilerplate(jsonFileBuilder().load("rdap_domain_add_grace_period.json")));
.isEqualTo(
addDomainBoilerplateNotices(
jsonFileBuilder().load("rdap_domain_add_grace_period.json")));
}
@Test
@@ -522,7 +519,8 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
assertAboutJson()
.that(generateActualJson("autorenew.lol"))
.isEqualTo(
addBoilerplate(jsonFileBuilder().load("rdap_domain_auto_renew_grace_period.json")));
addDomainBoilerplateNotices(
jsonFileBuilder().load("rdap_domain_auto_renew_grace_period.json")));
}
@Test
@@ -545,7 +543,7 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
assertAboutJson()
.that(generateActualJson("redemption.lol"))
.isEqualTo(
addBoilerplate(
addDomainBoilerplateNotices(
jsonFileBuilder().load("rdap_domain_pending_delete_redemption_grace_period.json")));
}
@@ -568,7 +566,8 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
assertAboutJson()
.that(generateActualJson("renew.lol"))
.isEqualTo(
addBoilerplate(jsonFileBuilder().load("rdap_domain_explicit_renew_grace_period.json")));
addDomainBoilerplateNotices(
jsonFileBuilder().load("rdap_domain_explicit_renew_grace_period.json")));
}
@Test
@@ -590,7 +589,8 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
assertAboutJson()
.that(generateActualJson("transfer.lol"))
.isEqualTo(
addBoilerplate(jsonFileBuilder().load("rdap_domain_transfer_grace_period.json")));
addDomainBoilerplateNotices(
jsonFileBuilder().load("rdap_domain_transfer_grace_period.json")));
}
@Test
@@ -631,12 +631,15 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
"rel",
"alternate",
"type",
"text/html")));
"text/html",
"value",
"https://example.tld/rdap/domain/example.lol")));
JsonObject actuaResponse = generateActualJson("example.lol");
JsonObject expectedErrorResponse = generateExpectedJsonError("example.lol blocked by BSA", 404);
expectedErrorResponse
.getAsJsonArray("notices")
.add(RdapTestHelper.GSON.toJsonTree(expectedBsaNotice));
assertAboutJson().that(generateActualJson("example.lol")).isEqualTo(expectedErrorResponse);
assertAboutJson().that(actuaResponse).isEqualTo(expectedErrorResponse);
assertThat(response.getStatus()).isEqualTo(404);
}

View File

@@ -473,8 +473,7 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
private JsonObject wrapInSearchReply(JsonObject obj) {
obj = RdapTestHelper.wrapInSearchReply("domainSearchResults", obj);
RdapTestHelper.addDomainBoilerplateNotices(obj, "https://example.tld/rdap/");
return obj;
return addDomainBoilerplateNotices(obj);
}
private void runSuccessfulTest(RequestType requestType, String queryString, JsonObject expected) {

View File

@@ -15,7 +15,6 @@
package google.registry.rdap;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.rdap.RdapTestHelper.loadJsonFile;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.testing.DatabaseHelper.persistSimpleResources;
@@ -28,7 +27,6 @@ import static google.registry.testing.GsonSubject.assertAboutJson;
import static org.mockito.Mockito.verify;
import com.google.common.collect.ImmutableList;
import com.google.gson.JsonObject;
import google.registry.model.contact.Contact;
import google.registry.model.host.Host;
import google.registry.model.registrar.Registrar;
@@ -39,13 +37,15 @@ import google.registry.rdap.RdapSearchResults.IncompletenessWarningType;
import google.registry.request.Action;
import google.registry.testing.FullFieldsTestEntityHelper;
import java.util.Optional;
import javax.annotation.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link RdapEntityAction}. */
class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
private static final String CONTACT_NAME = "(◕‿◕)";
private static final String CONTACT_ADDRESS = "\"1 Smiley Row\", \"Suite みんな\"";
RdapEntityActionTest() {
super(RdapEntityAction.class);
}
@@ -67,7 +67,7 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
registrant =
FullFieldsTestEntityHelper.makeAndPersistContact(
"8372808-REG",
"(◕‿◕)",
CONTACT_NAME,
"lol@cat.みんな",
ImmutableList.of("1 Smiley Row", "Suite みんな"),
clock.nowUtc(),
@@ -75,7 +75,7 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
adminContact =
FullFieldsTestEntityHelper.makeAndPersistContact(
"8372808-ADM",
"(◕‿◕)",
CONTACT_NAME,
"lol@cat.みんな",
ImmutableList.of("1 Smiley Row", "Suite みんな"),
clock.nowUtc(),
@@ -83,7 +83,7 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
techContact =
FullFieldsTestEntityHelper.makeAndPersistContact(
"8372808-TEC",
"(◕‿◕)",
CONTACT_NAME,
"lol@cat.みんな",
ImmutableList.of("1 Smiley Row", "Suite みんな"),
clock.nowUtc(),
@@ -110,7 +110,7 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
disconnectedContact =
FullFieldsTestEntityHelper.makeAndPersistContact(
"8372808-DIS",
"(◕‿◕)",
CONTACT_NAME,
"lol@cat.みんな",
ImmutableList.of("1 Smiley Row", "Suite みんな"),
clock.nowUtc(),
@@ -123,186 +123,191 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
clock.nowUtc().minusMonths(6));
}
private JsonObject generateExpectedJson(
String handle,
String fullName,
String status,
@Nullable String address,
String expectedOutputFile) {
return loadJsonFile(
expectedOutputFile,
"NAME", handle,
"FULLNAME", fullName,
"ADDRESS", (address == null) ? "\"1 Smiley Row\", \"Suite みんな\"" : address,
"TYPE", "entity",
"STATUS", status);
}
private JsonObject generateExpectedJsonWithTopLevelEntries(
String handle,
String expectedOutputFile) {
return generateExpectedJsonWithTopLevelEntries(
handle, "(◕‿◕)", "active", null, expectedOutputFile);
}
private JsonObject generateExpectedJsonWithTopLevelEntries(
String handle,
String fullName,
String status,
String address,
String expectedOutputFile) {
JsonObject obj = generateExpectedJson(handle, fullName, status, address, expectedOutputFile);
RdapTestHelper.addNonDomainBoilerplateNotices(obj, "https://example.tld/rdap/");
return obj;
}
private void runSuccessfulHandleTest(String handleQuery, String fileName) {
runSuccessfulHandleTest(handleQuery, "(◕‿◕)", "active", null, fileName);
}
private void runSuccessfulHandleTest(String handleQuery, String fullName, String fileName) {
runSuccessfulHandleTest(handleQuery, fullName, "active", null, fileName);
}
private void runSuccessfulHandleTest(
String handleQuery,
String fullName,
String rdapStatus,
String address,
String fileName) {
@Test
void testUnknownEntity_RoidPattern_notFound() {
assertAboutJson()
.that(generateActualJson(handleQuery))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
handleQuery, fullName, rdapStatus, address, fileName));
assertThat(response.getStatus()).isEqualTo(200);
}
private void runNotFoundTest(String handleQuery) {
assertAboutJson()
.that(generateActualJson(handleQuery))
.isEqualTo(generateExpectedJsonError(handleQuery + " not found", 404));
.that(generateActualJson("_MISSING-ENTITY_"))
.isEqualTo(generateExpectedJsonError("_MISSING-ENTITY_ not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
void testUnknownEntity_RoidPattern_notFound() {
runNotFoundTest("_MISSING-ENTITY_");
}
@Test
void testUnknownEntity_IanaPattern_notFound() {
runNotFoundTest("123");
assertAboutJson()
.that(generateActualJson("123"))
.isEqualTo(generateExpectedJsonError("123 not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
void testUnknownEntity_notRoidNotIana_notFound() {
// Since we allow search by registrar name, every string is a possible name
runNotFoundTest("some,random,string");
assertAboutJson()
.that(generateActualJson("some,random,string"))
.isEqualTo(generateExpectedJsonError("some,random,string not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
void testValidRegistrantContact_works() {
login("evilregistrar");
runSuccessfulHandleTest(registrant.getRepoId(), "rdap_associated_contact.json");
assertAboutJson()
.that(generateActualJson(registrant.getRepoId()))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullContact(registrant.getRepoId(), null, CONTACT_NAME, CONTACT_ADDRESS)
.load("rdap_associated_contact.json")));
}
@Test
void testValidRegistrantContact_found_asAdministrator() {
loginAsAdmin();
runSuccessfulHandleTest(registrant.getRepoId(), "rdap_associated_contact.json");
assertAboutJson()
.that(generateActualJson(registrant.getRepoId()))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullContact(registrant.getRepoId(), null, CONTACT_NAME, CONTACT_ADDRESS)
.load("rdap_associated_contact.json")));
}
@Test
void testValidRegistrantContact_found_notLoggedIn() {
runSuccessfulHandleTest(
registrant.getRepoId(),
"(◕‿◕)",
"active",
null,
"rdap_associated_contact_no_personal_data.json");
assertAboutJson()
.that(generateActualJson(registrant.getRepoId()))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullContact(registrant.getRepoId(), "active", CONTACT_NAME, CONTACT_ADDRESS)
.load("rdap_associated_contact_no_personal_data.json")));
}
@Test
void testValidRegistrantContact_found_loggedInAsOtherRegistrar() {
login("otherregistrar");
runSuccessfulHandleTest(
registrant.getRepoId(),
"(◕‿◕)",
"active",
null,
"rdap_associated_contact_no_personal_data.json");
assertAboutJson()
.that(generateActualJson(registrant.getRepoId()))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullContact(registrant.getRepoId(), "active", CONTACT_NAME, CONTACT_ADDRESS)
.load("rdap_associated_contact_no_personal_data.json")));
}
@Test
void testValidAdminContact_works() {
login("evilregistrar");
runSuccessfulHandleTest(adminContact.getRepoId(), "rdap_associated_contact.json");
assertAboutJson()
.that(generateActualJson(adminContact.getRepoId()))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullContact(adminContact.getRepoId(), null, CONTACT_NAME, CONTACT_ADDRESS)
.load("rdap_associated_contact.json")));
}
@Test
void testValidTechContact_works() {
login("evilregistrar");
runSuccessfulHandleTest(techContact.getRepoId(), "rdap_associated_contact.json");
assertAboutJson()
.that(generateActualJson(techContact.getRepoId()))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullContact(techContact.getRepoId(), null, CONTACT_NAME, CONTACT_ADDRESS)
.load("rdap_associated_contact.json")));
}
@Test
void testValidDisconnectedContact_works() {
login("evilregistrar");
runSuccessfulHandleTest(disconnectedContact.getRepoId(), "rdap_contact.json");
assertAboutJson()
.that(generateActualJson(disconnectedContact.getRepoId()))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullContact(
disconnectedContact.getRepoId(), "active", CONTACT_NAME, CONTACT_ADDRESS)
.load("rdap_contact.json")));
}
@Test
void testDeletedContact_notFound() {
runNotFoundTest(deletedContact.getRepoId());
String repoId = deletedContact.getRepoId();
assertAboutJson()
.that(generateActualJson(repoId))
.isEqualTo(generateExpectedJsonError(repoId + " not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
void testDeletedContact_notFound_includeDeletedSetFalse() {
action.includeDeletedParam = Optional.of(false);
runNotFoundTest(deletedContact.getRepoId());
String repoId = deletedContact.getRepoId();
assertAboutJson()
.that(generateActualJson(repoId))
.isEqualTo(generateExpectedJsonError(repoId + " not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
void testDeletedContact_notFound_notLoggedIn() {
action.includeDeletedParam = Optional.of(true);
runNotFoundTest(deletedContact.getRepoId());
String repoId = deletedContact.getRepoId();
assertAboutJson()
.that(generateActualJson(repoId))
.isEqualTo(generateExpectedJsonError(repoId + " not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
void testDeletedContact_notFound_loggedInAsDifferentRegistrar() {
login("idnregistrar");
action.includeDeletedParam = Optional.of(true);
runNotFoundTest(deletedContact.getRepoId());
String repoId = deletedContact.getRepoId();
assertAboutJson()
.that(generateActualJson(repoId))
.isEqualTo(generateExpectedJsonError(repoId + " not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
void testDeletedContact_found_loggedInAsCorrectRegistrar() {
login("evilregistrar");
action.includeDeletedParam = Optional.of(true);
runSuccessfulHandleTest(
deletedContact.getRepoId(),
"",
"inactive",
"",
"rdap_contact_deleted.json");
assertAboutJson()
.that(generateActualJson(deletedContact.getRepoId()))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addContact(deletedContact.getRepoId())
.load("rdap_contact_deleted.json")));
}
@Test
void testDeletedContact_found_loggedInAsAdmin() {
loginAsAdmin();
action.includeDeletedParam = Optional.of(true);
runSuccessfulHandleTest(
deletedContact.getRepoId(),
"",
"inactive",
"",
"rdap_contact_deleted.json");
assertAboutJson()
.that(generateActualJson(deletedContact.getRepoId()))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addContact(deletedContact.getRepoId())
.load("rdap_contact_deleted.json")));
}
@Test
void testRegistrar_found() {
runSuccessfulHandleTest("101", "Yes Virginia <script>", "rdap_registrar.json");
assertAboutJson()
.that(generateActualJson("101"))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullRegistrar("101", "Yes Virginia <script>", "active", null)
.load("rdap_registrar.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@Test
@@ -310,58 +315,97 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
assertAboutJson()
.that(generateActualJson("IDN%20Registrar"))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"102", "IDN Registrar", "active", null, "rdap_registrar.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullRegistrar("102", "IDN Registrar", "active", null)
.load("rdap_registrar.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@Test
void testRegistrar102_works() {
runSuccessfulHandleTest("102", "IDN Registrar", "rdap_registrar.json");
assertAboutJson()
.that(generateActualJson("102"))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullRegistrar("102", "IDN Registrar", "active", null)
.load("rdap_registrar.json")));
}
@Test
void testRegistrar103_works() {
runSuccessfulHandleTest("103", "Multilevel Registrar", "rdap_registrar.json");
assertAboutJson()
.that(generateActualJson("103"))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullRegistrar("103", "Multilevel Registrar", "active", null)
.load("rdap_registrar.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@Test
void testRegistrar104_notFound() {
runNotFoundTest("104");
assertAboutJson()
.that(generateActualJson("104"))
.isEqualTo(generateExpectedJsonError("104 not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
void testRegistrar104_notFound_deletedFlagWhenNotLoggedIn() {
action.includeDeletedParam = Optional.of(true);
runNotFoundTest("104");
assertAboutJson()
.that(generateActualJson("104"))
.isEqualTo(generateExpectedJsonError("104 not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
void testRegistrar104_found_deletedFlagWhenLoggedIn() {
login("deletedregistrar");
action.includeDeletedParam = Optional.of(true);
runSuccessfulHandleTest(
"104", "Yes Virginia <script>", "inactive", null, "rdap_registrar.json");
assertAboutJson()
.that(generateActualJson("104"))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullRegistrar("104", "Yes Virginia <script>", "inactive", null)
.load("rdap_registrar.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@Test
void testRegistrar104_notFound_deletedFlagWhenLoggedInAsOther() {
login("1tldregistrar");
action.includeDeletedParam = Optional.of(true);
runNotFoundTest("104");
assertAboutJson()
.that(generateActualJson("104"))
.isEqualTo(generateExpectedJsonError("104 not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
void testRegistrar104_found_deletedFlagWhenLoggedInAsAdmin() {
loginAsAdmin();
action.includeDeletedParam = Optional.of(true);
runSuccessfulHandleTest(
"104", "Yes Virginia <script>", "inactive", null, "rdap_registrar.json");
assertAboutJson()
.that(generateActualJson("104"))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullRegistrar("104", "Yes Virginia <script>", "inactive", null)
.load("rdap_registrar.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@Test
void testRegistrar105_doesNotExist() {
runNotFoundTest("105");
assertAboutJson()
.that(generateActualJson("105"))
.isEqualTo(generateExpectedJsonError("105 not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
@@ -370,8 +414,10 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
assertAboutJson()
.that(generateActualJson(techContact.getRepoId() + "?key=value"))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
techContact.getRepoId(), "rdap_associated_contact.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullContact(techContact.getRepoId(), null, CONTACT_NAME, CONTACT_ADDRESS)
.load("rdap_associated_contact.json")));
assertThat(response.getStatus()).isEqualTo(200);
}

View File

@@ -15,7 +15,6 @@
package google.registry.rdap;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.rdap.RdapTestHelper.loadJsonFile;
import static google.registry.rdap.RdapTestHelper.parseJsonObject;
import static google.registry.request.Action.Method.GET;
import static google.registry.testing.DatabaseHelper.createTld;
@@ -30,7 +29,6 @@ import static google.registry.testing.GsonSubject.assertAboutJson;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@@ -45,13 +43,15 @@ import google.registry.testing.FakeResponse;
import google.registry.testing.FullFieldsTestEntityHelper;
import java.net.URLDecoder;
import java.util.Optional;
import javax.annotation.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link RdapEntitySearchAction}. */
class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySearchAction> {
private static final String BINKY_ADDRESS = "\"123 Blinky St\", \"Blinkyland\"";
private static final String BINKY_FULL_NAME = "Blinky (赤ベイ)";
RdapEntitySearchActionTest() {
super(RdapEntitySearchAction.class);
}
@@ -128,7 +128,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
FullFieldsTestEntityHelper.makeAndPersistContact(
"blinky",
"Blinky (赤ベイ)",
BINKY_FULL_NAME,
"blinky@b.tld",
ImmutableList.of("123 Blinky St", "Blinkyland"),
clock.nowUtc(),
@@ -150,45 +150,9 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
action.subtypeParam = Optional.empty();
}
private JsonObject generateExpectedJson(String expectedOutputFile) {
return loadJsonFile(expectedOutputFile, "TYPE", "entity");
}
private JsonObject generateExpectedJson(
String handle,
String expectedOutputFile) {
return generateExpectedJson(handle, null, "active", null, expectedOutputFile);
}
private JsonObject generateExpectedJson(
String handle,
@Nullable String fullName,
String status,
@Nullable String address,
String expectedOutputFile) {
ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<>();
builder.put("NAME", handle);
if (fullName != null) {
builder.put("FULLNAME", fullName);
}
if (address != null) {
builder.put("ADDRESS", address);
}
builder.put("TYPE", "entity");
builder.put("STATUS", status);
return loadJsonFile(expectedOutputFile, builder.build());
}
private JsonObject generateExpectedJsonForEntity(
String handle,
String fullName,
String status,
@Nullable String address,
String expectedOutputFile) {
JsonObject obj = generateExpectedJson(handle, fullName, status, address, expectedOutputFile);
obj = RdapTestHelper.wrapInSearchReply("entitySearchResults", obj);
RdapTestHelper.addNonDomainBoilerplateNotices(obj, "https://example.tld/rdap/");
return obj;
private JsonObject addBoilerplate(JsonObject jsonObject) {
jsonObject = RdapTestHelper.wrapInSearchReply("entitySearchResults", jsonObject);
return addPermanentBoilerplateNotices(jsonObject);
}
private void createManyContactsAndRegistrars(
@@ -259,38 +223,6 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
verifyMetrics(numContactsRetrieved);
}
private void runSuccessfulNameTestWithBlinky(String queryString, String fileName) {
runSuccessfulNameTest(
queryString,
"2-ROID",
"Blinky (赤ベイ)",
"active",
"\"123 Blinky St\", \"Blinkyland\"",
fileName);
}
private void runSuccessfulNameTest(
String queryString,
String handle,
@Nullable String fullName,
String fileName) {
runSuccessfulNameTest(queryString, handle, fullName, "active", null, fileName);
}
private void runSuccessfulNameTest(
String queryString,
String handle,
@Nullable String fullName,
String status,
@Nullable String address,
String fileName) {
rememberWildcardType(queryString);
assertAboutJson()
.that(generateActualJsonWithFullName(queryString))
.isEqualTo(generateExpectedJsonForEntity(handle, fullName, status, address, fileName));
assertThat(response.getStatus()).isEqualTo(200);
}
private void runNotFoundNameTest(String queryString) {
rememberWildcardType(queryString);
assertAboutJson()
@@ -299,38 +231,6 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
assertThat(response.getStatus()).isEqualTo(404);
}
private void runSuccessfulHandleTestWithBlinky(String queryString, String fileName) {
runSuccessfulHandleTest(
queryString,
"2-ROID",
"Blinky (赤ベイ)",
"active",
"\"123 Blinky St\", \"Blinkyland\"",
fileName);
}
private void runSuccessfulHandleTest(
String queryString,
String handle,
@Nullable String fullName,
String fileName) {
runSuccessfulHandleTest(queryString, handle, fullName, "active", null, fileName);
}
private void runSuccessfulHandleTest(
String queryString,
String handle,
@Nullable String fullName,
String status,
@Nullable String address,
String fileName) {
rememberWildcardType(queryString);
assertAboutJson()
.that(generateActualJsonWithHandle(queryString))
.isEqualTo(generateExpectedJsonForEntity(handle, fullName, status, address, fileName));
assertThat(response.getStatus()).isEqualTo(200);
}
private void runNotFoundHandleTest(String queryString) {
rememberWildcardType(queryString);
assertAboutJson()
@@ -470,7 +370,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testInvalidSubtype_rejected() {
action.subtypeParam = Optional.of("Space Aliens");
assertAboutJson()
.that(generateActualJsonWithFullName("Blinky (赤ベイ)"))
.that(generateActualJsonWithFullName(BINKY_FULL_NAME))
.isEqualTo(
generateExpectedJsonError(
"Subtype parameter must specify contacts, registrars or all", 400));
@@ -482,23 +382,44 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
@Test
void testNameMatchContact_found() {
login("2-RegistrarTest");
runSuccessfulNameTestWithBlinky("Blinky (赤ベイ)", "rdap_contact.json");
rememberWildcardType(BINKY_FULL_NAME);
assertAboutJson()
.that(generateActualJsonWithFullName(BINKY_FULL_NAME))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@Test
void testNameMatchContact_found_subtypeAll() {
login("2-RegistrarTest");
rememberWildcardType(BINKY_FULL_NAME);
action.subtypeParam = Optional.of("aLl");
runSuccessfulNameTestWithBlinky("Blinky (赤ベイ)", "rdap_contact.json");
assertAboutJson()
.that(generateActualJsonWithFullName(BINKY_FULL_NAME))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@Test
void testNameMatchContact_found_subtypeContacts() {
login("2-RegistrarTest");
rememberWildcardType(BINKY_FULL_NAME);
action.subtypeParam = Optional.of("cONTACTS");
runSuccessfulNameTestWithBlinky("Blinky (赤ベイ)", "rdap_contact.json");
assertAboutJson()
.that(generateActualJsonWithFullName(BINKY_FULL_NAME))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@@ -506,15 +427,22 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testNameMatchContact_notFound_subtypeRegistrars() {
login("2-RegistrarTest");
action.subtypeParam = Optional.of("Registrars");
runNotFoundNameTest("Blinky (赤ベイ)");
runNotFoundNameTest(BINKY_FULL_NAME);
verifyErrorMetrics(0);
}
@Test
void testNameMatchContact_found_specifyingSameRegistrar() {
login("2-RegistrarTest");
rememberWildcardType(BINKY_FULL_NAME);
action.registrarParam = Optional.of("2-RegistrarTest");
runSuccessfulNameTestWithBlinky("Blinky (赤ベイ)", "rdap_contact.json");
assertAboutJson()
.that(generateActualJsonWithFullName(BINKY_FULL_NAME))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@@ -522,35 +450,48 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testNameMatchContact_notFound_specifyingOtherRegistrar() {
login("2-RegistrarTest");
action.registrarParam = Optional.of("2-RegistrarInact");
runNotFoundNameTest("Blinky (赤ベイ)");
runNotFoundNameTest(BINKY_FULL_NAME);
verifyErrorMetrics(0);
}
@Test
void testNameMatchContact_found_asAdministrator() {
loginAsAdmin();
rememberWildcardType("Blinky (赤ベイ)");
runSuccessfulNameTestWithBlinky("Blinky (赤ベイ)", "rdap_contact.json");
rememberWildcardType(BINKY_FULL_NAME);
assertAboutJson()
.that(generateActualJsonWithFullName(BINKY_FULL_NAME))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@Test
void testNameMatchContact_notFound_notLoggedIn() {
runNotFoundNameTest("Blinky (赤ベイ)");
runNotFoundNameTest(BINKY_FULL_NAME);
verifyErrorMetrics(0);
}
@Test
void testNameMatchContact_notFound_loggedInAsOtherRegistrar() {
login("2-Registrar");
runNotFoundNameTest("Blinky (赤ベイ)");
runNotFoundNameTest(BINKY_FULL_NAME);
verifyErrorMetrics(0);
}
@Test
void testNameMatchContact_found_wildcard() {
login("2-RegistrarTest");
runSuccessfulNameTestWithBlinky("Blinky*", "rdap_contact.json");
rememberWildcardType("Blinky*");
assertAboutJson()
.that(generateActualJsonWithFullName("Blinky*"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@@ -558,7 +499,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testNameMatchContact_found_wildcardSpecifyingSameRegistrar() {
login("2-RegistrarTest");
action.registrarParam = Optional.of("2-RegistrarTest");
runSuccessfulNameTestWithBlinky("Blinky*", "rdap_contact.json");
rememberWildcardType("Blinky*");
assertAboutJson()
.that(generateActualJsonWithFullName("Blinky*"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@@ -576,7 +524,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
rememberWildcardType("Blin*");
assertAboutJson()
.that(generateActualJsonWithFullName("Blin*"))
.isEqualTo(generateExpectedJson("rdap_multiple_contacts2.json"));
.isEqualTo(jsonFileBuilder().load("rdap_multiple_contacts2.json"));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(2);
}
@@ -615,8 +563,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
@Test
void testNameMatchRegistrar_found() {
login("2-RegistrarTest");
runSuccessfulNameTest(
"Yes Virginia <script>", "20", "Yes Virginia <script>", "rdap_registrar.json");
rememberWildcardType("Yes Virginia <script>");
assertAboutJson()
.that(generateActualJsonWithFullName("Yes Virginia <script>"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("20", "Yes Virginia <script>", "active", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@@ -624,8 +578,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testNameMatchRegistrar_found_subtypeAll() {
login("2-RegistrarTest");
action.subtypeParam = Optional.of("all");
runSuccessfulNameTest(
"Yes Virginia <script>", "20", "Yes Virginia <script>", "rdap_registrar.json");
rememberWildcardType("Yes Virginia <script>");
assertAboutJson()
.that(generateActualJsonWithFullName("Yes Virginia <script>"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("20", "Yes Virginia <script>", "active", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@@ -633,8 +593,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testNameMatchRegistrar_found_subtypeRegistrars() {
login("2-RegistrarTest");
action.subtypeParam = Optional.of("REGISTRARS");
runSuccessfulNameTest(
"Yes Virginia <script>", "20", "Yes Virginia <script>", "rdap_registrar.json");
rememberWildcardType("Yes Virginia <script>");
assertAboutJson()
.that(generateActualJsonWithFullName("Yes Virginia <script>"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("20", "Yes Virginia <script>", "active", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@@ -649,8 +615,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
@Test
void testNameMatchRegistrar_found_specifyingSameRegistrar() {
action.registrarParam = Optional.of("2-Registrar");
runSuccessfulNameTest(
"Yes Virginia <script>", "20", "Yes Virginia <script>", "rdap_registrar.json");
rememberWildcardType("Yes Virginia <script>");
assertAboutJson()
.that(generateActualJsonWithFullName("Yes Virginia <script>"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("20", "Yes Virginia <script>", "active", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@@ -666,10 +638,9 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
login("2-RegistrarTest");
createManyContactsAndRegistrars(4, 0, registrarTest);
rememberWildcardType("Entity *");
// JsonObject foo = generateActualJsonWithFullName("Entity *");
assertAboutJson()
.that(generateActualJsonWithFullName("Entity *"))
.isEqualTo(generateExpectedJson("rdap_nontruncated_contacts.json"));
.isEqualTo(jsonFileBuilder().load("rdap_nontruncated_contacts.json"));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(4);
}
@@ -682,8 +653,9 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
assertAboutJson()
.that(generateActualJsonWithFullName("Entity *"))
.isEqualTo(
generateExpectedJson(
"fn=Entity+*&cursor=YzpFbnRpdHkgNA%3D%3D", "rdap_truncated_contacts.json"));
jsonFileBuilder()
.put("NAME", "fn=Entity+*&cursor=YzpFbnRpdHkgNA%3D%3D")
.load("rdap_truncated_contacts.json"));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(5, IncompletenessWarningType.TRUNCATED);
}
@@ -696,8 +668,9 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
assertAboutJson()
.that(generateActualJsonWithFullName("Entity *"))
.isEqualTo(
generateExpectedJson(
"fn=Entity+*&cursor=YzpFbnRpdHkgNA%3D%3D", "rdap_truncated_contacts.json"));
jsonFileBuilder()
.put("NAME", "fn=Entity+*&cursor=YzpFbnRpdHkgNA%3D%3D")
.load("rdap_truncated_contacts.json"));
assertThat(response.getStatus()).isEqualTo(200);
// For contacts, we only need to fetch one result set's worth (plus one).
verifyMetrics(5, IncompletenessWarningType.TRUNCATED);
@@ -728,7 +701,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
rememberWildcardType("Entity *");
assertAboutJson()
.that(generateActualJsonWithFullName("Entity *"))
.isEqualTo(generateExpectedJson("rdap_nontruncated_registrars.json"));
.isEqualTo(jsonFileBuilder().load("rdap_nontruncated_registrars.json"));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(0);
}
@@ -740,8 +713,9 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
assertAboutJson()
.that(generateActualJsonWithFullName("Entity *"))
.isEqualTo(
generateExpectedJson(
"fn=Entity+*&cursor=cjpFbnRpdHkgNA%3D%3D", "rdap_truncated_registrars.json"));
jsonFileBuilder()
.put("NAME", "fn=Entity+*&cursor=cjpFbnRpdHkgNA%3D%3D")
.load("rdap_truncated_registrars.json"));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(0, IncompletenessWarningType.TRUNCATED);
}
@@ -753,8 +727,9 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
assertAboutJson()
.that(generateActualJsonWithFullName("Entity *"))
.isEqualTo(
generateExpectedJson(
"fn=Entity+*&cursor=cjpFbnRpdHkgNA%3D%3D", "rdap_truncated_registrars.json"));
jsonFileBuilder()
.put("NAME", "fn=Entity+*&cursor=cjpFbnRpdHkgNA%3D%3D")
.load("rdap_truncated_registrars.json"));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(0, IncompletenessWarningType.TRUNCATED);
}
@@ -815,8 +790,9 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
assertAboutJson()
.that(generateActualJsonWithFullName("Entity *"))
.isEqualTo(
generateExpectedJson(
"fn=Entity+*&cursor=cjpFbnRpdHkgNA%3D%3D", "rdap_truncated_mixed_entities.json"));
jsonFileBuilder()
.put("NAME", "fn=Entity+*&cursor=cjpFbnRpdHkgNA%3D%3D")
.load("rdap_truncated_mixed_entities.json"));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(3, IncompletenessWarningType.TRUNCATED);
}
@@ -845,7 +821,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
rememberWildcardType("Entity *");
assertAboutJson()
.that(generateActualJsonWithFullName("Entity *"))
.isEqualTo(generateExpectedJson("rdap_nontruncated_contacts.json"));
.isEqualTo(jsonFileBuilder().load("rdap_nontruncated_contacts.json"));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(4);
}
@@ -855,8 +831,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
login("2-RegistrarTest");
action.subtypeParam = Optional.of("registrars");
createManyContactsAndRegistrars(1, 1, registrarTest);
runSuccessfulNameTest(
"Entity *", "301", "Entity 2", "rdap_registrar.json");
rememberWildcardType("Entity *");
assertAboutJson()
.that(generateActualJsonWithFullName("Entity *"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("301", "Entity 2", "active", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@@ -878,7 +860,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testNameMatchRegistrar_found_inactiveAsSameRegistrar() {
action.includeDeletedParam = Optional.of(true);
login("2-RegistrarInact");
runSuccessfulNameTest("No Way", "21", "No Way", "inactive", null, "rdap_registrar.json");
rememberWildcardType("No Way");
assertAboutJson()
.that(generateActualJsonWithFullName("No Way"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("21", "No Way", "inactive", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@@ -886,7 +875,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testNameMatchRegistrar_found_inactiveAsAdmin() {
action.includeDeletedParam = Optional.of(true);
loginAsAdmin();
runSuccessfulNameTest("No Way", "21", "No Way", "inactive", null, "rdap_registrar.json");
rememberWildcardType("No Way");
assertAboutJson()
.that(generateActualJsonWithFullName("No Way"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("21", "No Way", "inactive", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@@ -908,8 +904,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testNameMatchRegistrar_found_testAsSameRegistrar() {
action.includeDeletedParam = Optional.of(true);
login("2-RegistrarTest");
runSuccessfulNameTest(
"Da Test Registrar", "not applicable", "Da Test Registrar", "rdap_registrar_test.json");
rememberWildcardType("Da Test Registrar");
assertAboutJson()
.that(generateActualJsonWithFullName("Da Test Registrar"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("not applicable", "Da Test Registrar", "active", null)
.load("rdap_registrar_test.json")));
verifyMetrics(0);
}
@@ -917,15 +919,28 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testNameMatchRegistrar_found_testAsAdmin() {
action.includeDeletedParam = Optional.of(true);
loginAsAdmin();
runSuccessfulNameTest(
"Da Test Registrar", "not applicable", "Da Test Registrar", "rdap_registrar_test.json");
rememberWildcardType("Da Test Registrar");
assertAboutJson()
.that(generateActualJsonWithFullName("Da Test Registrar"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("not applicable", "Da Test Registrar", "active", null)
.load("rdap_registrar_test.json")));
verifyMetrics(0);
}
@Test
void testHandleMatchContact_found() {
login("2-RegistrarTest");
runSuccessfulHandleTestWithBlinky("2-ROID", "rdap_contact.json");
rememberWildcardType("2-ROID");
assertAboutJson()
.that(generateActualJsonWithHandle("2-ROID"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@@ -933,7 +948,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testHandleMatchContact_found_subtypeAll() {
login("2-RegistrarTest");
action.subtypeParam = Optional.of("all");
runSuccessfulHandleTestWithBlinky("2-ROID", "rdap_contact.json");
rememberWildcardType("2-ROID");
assertAboutJson()
.that(generateActualJsonWithHandle("2-ROID"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@@ -941,7 +963,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testHandleMatchContact_found_subtypeContacts() {
login("2-RegistrarTest");
action.subtypeParam = Optional.of("contacts");
runSuccessfulHandleTestWithBlinky("2-ROID", "rdap_contact.json");
rememberWildcardType("2-ROID");
assertAboutJson()
.that(generateActualJsonWithHandle("2-ROID"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@@ -956,7 +985,12 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
@Test
void testHandleMatchContact_found_specifyingSameRegistrar() {
action.registrarParam = Optional.of("2-RegistrarTest");
runSuccessfulHandleTestWithBlinky("2-ROID", "rdap_contact_no_personal_data_with_remark.json");
rememberWildcardType("2-ROID");
assertAboutJson()
.that(generateActualJsonWithHandle("2-ROID"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder().load("rdap_contact_no_personal_data_with_remark.json")));
verifyMetrics(1);
}
@@ -986,13 +1020,12 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testHandleMatchContact_found_deletedWhenLoggedInAsSameRegistrar() {
login("2-Registrar");
action.includeDeletedParam = Optional.of(true);
runSuccessfulHandleTest(
"6-ROID",
"6-ROID",
"",
"inactive",
"",
"rdap_contact_deleted.json");
rememberWildcardType("6-ROID");
assertAboutJson()
.that(generateActualJsonWithHandle("6-ROID"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder().addContact("6-ROID").load("rdap_contact_deleted.json")));
verifyMetrics(1);
}
@@ -1000,13 +1033,12 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testHandleMatchContact_found_deletedWhenLoggedInAsAdmin() {
loginAsAdmin();
action.includeDeletedParam = Optional.of(true);
runSuccessfulHandleTest(
"6-ROID",
"6-ROID",
"",
"inactive",
"",
"rdap_contact_deleted.json");
rememberWildcardType("6-ROID");
assertAboutJson()
.that(generateActualJsonWithHandle("6-ROID"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder().addContact("6-ROID").load("rdap_contact_deleted.json")));
verifyMetrics(1);
}
@@ -1029,13 +1061,12 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testHandleMatchContact_found_deletedWildcardWhenLoggedInAsSameRegistrar() {
login("2-Registrar");
action.includeDeletedParam = Optional.of(true);
runSuccessfulHandleTest(
"6-ROI*",
"6-ROID",
"",
"inactive",
"",
"rdap_contact_deleted.json");
rememberWildcardType("6-ROI*");
assertAboutJson()
.that(generateActualJsonWithHandle("6-ROI*"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder().addContact("6-ROID").load("rdap_contact_deleted.json")));
verifyMetrics(1);
}
@@ -1043,33 +1074,53 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testHandleMatchContact_found_deletedWildcardWhenLoggedInAsAdmin() {
loginAsAdmin();
action.includeDeletedParam = Optional.of(true);
runSuccessfulHandleTest(
"6-ROI*",
"6-ROID",
"",
"inactive",
"",
"rdap_contact_deleted.json");
rememberWildcardType("6-ROI*");
assertAboutJson()
.that(generateActualJsonWithHandle("6-ROI*"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder().addContact("6-ROID").load("rdap_contact_deleted.json")));
verifyMetrics(1);
}
@Test
void testHandleMatchRegistrar_found() {
runSuccessfulHandleTest("20", "20", "Yes Virginia <script>", "rdap_registrar.json");
rememberWildcardType("20");
assertAboutJson()
.that(generateActualJsonWithHandle("20"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("20", "Yes Virginia <script>", "active", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@Test
void testHandleMatchRegistrar_found_subtypeAll() {
action.subtypeParam = Optional.of("all");
runSuccessfulHandleTest("20", "20", "Yes Virginia <script>", "rdap_registrar.json");
rememberWildcardType("20");
assertAboutJson()
.that(generateActualJsonWithHandle("20"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("20", "Yes Virginia <script>", "active", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@Test
void testHandleMatchRegistrar_found_subtypeRegistrars() {
action.subtypeParam = Optional.of("registrars");
runSuccessfulHandleTest("20", "20", "Yes Virginia <script>", "rdap_registrar.json");
rememberWildcardType("20");
assertAboutJson()
.that(generateActualJsonWithHandle("20"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("20", "Yes Virginia <script>", "active", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@@ -1083,7 +1134,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
@Test
void testHandleMatchRegistrar_found_specifyingSameRegistrar() {
action.registrarParam = Optional.of("2-Registrar");
runSuccessfulHandleTest("20", "20", "Yes Virginia <script>", "rdap_registrar.json");
rememberWildcardType("20");
assertAboutJson()
.that(generateActualJsonWithHandle("20"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("20", "Yes Virginia <script>", "active", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@@ -1098,14 +1156,28 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testHandleMatchContact_found_wildcardWithResultSetSizeOne() {
login("2-RegistrarTest");
action.rdapResultSetMaxSize = 1;
runSuccessfulHandleTestWithBlinky("2-R*", "rdap_contact.json");
rememberWildcardType("2-R*");
assertAboutJson()
.that(generateActualJsonWithHandle("2-R*"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@Test
void testHandleMatchContact_found_wildcard() {
login("2-RegistrarTest");
runSuccessfulHandleTestWithBlinky("2-RO*", "rdap_contact.json");
rememberWildcardType("2-R*");
assertAboutJson()
.that(generateActualJsonWithHandle("2-R*"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@@ -1113,7 +1185,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testHandleMatchContact_found_wildcardSpecifyingSameRegistrar() {
action.registrarParam = Optional.of("2-RegistrarTest");
login("2-RegistrarTest");
runSuccessfulHandleTestWithBlinky("2-RO*", "rdap_contact.json");
rememberWildcardType("2-RO*");
assertAboutJson()
.that(generateActualJsonWithHandle("2-RO*"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@@ -1128,7 +1207,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
@Test
void testHandleMatchContact_found_deleted() {
login("2-RegistrarTest");
runSuccessfulHandleTestWithBlinky("2-RO*", "rdap_contact.json");
rememberWildcardType("2-R*");
assertAboutJson()
.that(generateActualJsonWithHandle("2-R*"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@@ -1245,7 +1331,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testHandleMatchRegistrar_found_inactiveAsSameRegistrar() {
action.includeDeletedParam = Optional.of(true);
login("2-RegistrarInact");
runSuccessfulHandleTest("21", "21", "No Way", "inactive", null, "rdap_registrar.json");
rememberWildcardType("21");
assertAboutJson()
.that(generateActualJsonWithHandle("21"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("21", "No Way", "inactive", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@@ -1253,7 +1346,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testHandleMatchRegistrar_found_inactiveAsAdmin() {
action.includeDeletedParam = Optional.of(true);
loginAsAdmin();
runSuccessfulHandleTest("21", "21", "No Way", "inactive", null, "rdap_registrar.json");
rememberWildcardType("21");
assertAboutJson()
.that(generateActualJsonWithHandle("21"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("21", "No Way", "inactive", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
}

View File

@@ -48,13 +48,15 @@ class RdapHelpActionTest extends RdapActionBaseTestCase<RdapHelpAction> {
@Test
void testHelpActionDefault_getsIndex() {
assertThat(generateActualJson("")).isEqualTo(loadJsonFile("rdap_help_index.json"));
assertThat(generateActualJson(""))
.isEqualTo(loadJsonFile("rdap_help_index.json", "POSSIBLE_SLASH", ""));
assertThat(response.getStatus()).isEqualTo(200);
}
@Test
void testHelpActionSlash_getsIndex() {
assertThat(generateActualJson("/")).isEqualTo(loadJsonFile("rdap_help_index.json"));
assertThat(generateActualJson("/"))
.isEqualTo(loadJsonFile("rdap_help_index.json", "POSSIBLE_SLASH", "/"));
assertThat(response.getStatus()).isEqualTo(200);
}

View File

@@ -15,15 +15,12 @@
package google.registry.rdap;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.rdap.RdapTestHelper.loadJsonFile;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrar;
import static google.registry.testing.GsonSubject.assertAboutJson;
import static org.mockito.Mockito.verify;
import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonObject;
import google.registry.model.registrar.Registrar;
import google.registry.rdap.RdapMetrics.EndpointType;
import google.registry.rdap.RdapMetrics.SearchType;
@@ -32,7 +29,6 @@ import google.registry.rdap.RdapSearchResults.IncompletenessWarningType;
import google.registry.request.Action;
import google.registry.testing.FullFieldsTestEntityHelper;
import java.util.Optional;
import javax.annotation.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -72,37 +68,6 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
"ns1.domain.external", "9.10.11.12", clock.nowUtc().minusYears(1));
}
private JsonObject generateExpectedJson(
String name,
@Nullable ImmutableMap<String, String> otherSubstitutions,
String expectedOutputFile) {
ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<>();
builder.put("TYPE", "nameserver");
builder.put("NAME", name);
boolean punycodeSet = false;
if (otherSubstitutions != null) {
builder.putAll(otherSubstitutions);
if (otherSubstitutions.containsKey("PUNYCODENAME")) {
punycodeSet = true;
}
}
if (!punycodeSet) {
builder.put("PUNYCODENAME", name);
}
return loadJsonFile(
expectedOutputFile,
builder.build());
}
private JsonObject generateExpectedJsonWithTopLevelEntries(
String name,
@Nullable ImmutableMap<String, String> otherSubstitutions,
String expectedOutputFile) {
JsonObject obj = generateExpectedJson(name, otherSubstitutions, expectedOutputFile);
RdapTestHelper.addNonDomainBoilerplateNotices(obj, "https://example.tld/rdap/");
return obj;
}
@Test
void testInvalidNameserver_returns400() {
assertAboutJson()
@@ -126,14 +91,11 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
assertAboutJson()
.that(generateActualJson("ns1.cat.lol"))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"ns1.cat.lol",
ImmutableMap.of(
"HANDLE", "2-ROID",
"ADDRESSTYPE", "v4",
"ADDRESS", "1.2.3.4",
"STATUS", "active"),
"rdap_host.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addNameserver("ns1.cat.lol", "2-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.4", "STATUS", "active")
.load("rdap_host.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@@ -142,14 +104,11 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
assertAboutJson()
.that(generateActualJson("ns1.cat.lol."))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"ns1.cat.lol",
ImmutableMap.of(
"HANDLE", "2-ROID",
"ADDRESSTYPE", "v4",
"ADDRESS", "1.2.3.4",
"STATUS", "active"),
"rdap_host.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addNameserver("ns1.cat.lol", "2-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.4", "STATUS", "active")
.load("rdap_host.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@@ -158,14 +117,11 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
assertAboutJson()
.that(generateActualJson("Ns1.CaT.lOl."))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"ns1.cat.lol",
ImmutableMap.of(
"HANDLE", "2-ROID",
"ADDRESSTYPE", "v4",
"ADDRESS", "1.2.3.4",
"STATUS", "active"),
"rdap_host.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addNameserver("ns1.cat.lol", "2-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.4", "STATUS", "active")
.load("rdap_host.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@@ -174,14 +130,11 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
assertAboutJson()
.that(generateActualJson("ns1.cat.lol?key=value"))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"ns1.cat.lol",
ImmutableMap.of(
"HANDLE", "2-ROID",
"ADDRESSTYPE", "v4",
"ADDRESS", "1.2.3.4",
"STATUS", "active"),
"rdap_host.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addNameserver("ns1.cat.lol", "2-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.4", "STATUS", "active")
.load("rdap_host.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@@ -190,15 +143,11 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
assertAboutJson()
.that(generateActualJson("ns1.cat.みんな"))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"ns1.cat.みんな",
ImmutableMap.of(
"PUNYCODENAME", "ns1.cat.xn--q9jyb4c",
"HANDLE", "5-ROID",
"ADDRESSTYPE", "v6",
"ADDRESS", "bad:f00d:cafe::15:beef",
"STATUS", "active"),
"rdap_host_unicode.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addNameserver("ns1.cat.みんな", "5-ROID")
.putAll("ADDRESSTYPE", "v6", "ADDRESS", "bad:f00d:cafe::15:beef")
.load("rdap_host_unicode.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@@ -207,15 +156,11 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
assertAboutJson()
.that(generateActualJson("ns1.cat.xn--q9jyb4c"))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"ns1.cat.みんな",
ImmutableMap.of(
"PUNYCODENAME", "ns1.cat.xn--q9jyb4c",
"HANDLE", "5-ROID",
"ADDRESSTYPE", "v6",
"ADDRESS", "bad:f00d:cafe::15:beef",
"STATUS", "active"),
"rdap_host_unicode.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addNameserver("ns1.cat.みんな", "5-ROID")
.putAll("ADDRESSTYPE", "v6", "ADDRESS", "bad:f00d:cafe::15:beef")
.load("rdap_host_unicode.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@@ -224,14 +169,11 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
assertAboutJson()
.that(generateActualJson("ns1.domain.1.tld"))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"ns1.domain.1.tld",
ImmutableMap.of(
"HANDLE", "8-ROID",
"ADDRESSTYPE", "v4",
"ADDRESS", "5.6.7.8",
"STATUS", "active"),
"rdap_host.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addNameserver("ns1.domain.1.tld", "8-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "5.6.7.8", "STATUS", "active")
.load("rdap_host.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@@ -240,14 +182,11 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
assertAboutJson()
.that(generateActualJson("ns1.domain.external"))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"ns1.domain.external",
ImmutableMap.of(
"HANDLE", "C-ROID",
"ADDRESSTYPE", "v4",
"ADDRESS", "9.10.11.12",
"STATUS", "active"),
"rdap_host.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addNameserver("ns1.domain.external", "C-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "9.10.11.12", "STATUS", "active")
.load("rdap_host.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@@ -287,14 +226,11 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
assertAboutJson()
.that(generateActualJson("nsdeleted.cat.lol"))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"nsdeleted.cat.lol",
ImmutableMap.of(
"HANDLE", "A-ROID",
"ADDRESSTYPE", "v4",
"ADDRESS", "1.2.3.4",
"STATUS", "inactive"),
"rdap_host.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addNameserver("nsdeleted.cat.lol", "A-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.4", "STATUS", "inactive")
.load("rdap_host.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@@ -305,14 +241,11 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
assertAboutJson()
.that(generateActualJson("nsdeleted.cat.lol"))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"nsdeleted.cat.lol",
ImmutableMap.of(
"HANDLE", "A-ROID",
"ADDRESSTYPE", "v4",
"ADDRESS", "1.2.3.4",
"STATUS", "inactive"),
"rdap_host.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addNameserver("nsdeleted.cat.lol", "A-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.4", "STATUS", "inactive")
.load("rdap_host.json")));
assertThat(response.getStatus()).isEqualTo(200);
}

View File

@@ -158,26 +158,9 @@ class RdapNameserverSearchActionTest extends RdapSearchActionTestCase<RdapNamese
action.nameParam = Optional.empty();
}
private JsonObject generateExpectedJsonForNameserver(
String name,
String punycodeName,
String handle,
String ipAddressType,
String ipAddress,
String expectedOutputFile) {
JsonObject obj =
loadJsonFile(
expectedOutputFile,
"NAME", name,
"PUNYCODENAME", punycodeName,
"HANDLE", handle,
"ADDRESSTYPE", ipAddressType,
"ADDRESS", ipAddress,
"STATUS", "active",
"TYPE", "nameserver");
obj = RdapTestHelper.wrapInSearchReply("nameserverSearchResults", obj);
RdapTestHelper.addNonDomainBoilerplateNotices(obj, "https://example.tld/rdap/");
return obj;
private JsonObject addBoilerplate(JsonObject jsonObject) {
jsonObject = RdapTestHelper.wrapInSearchReply("nameserverSearchResults", jsonObject);
return addPermanentBoilerplateNotices(jsonObject);
}
private void createManyHosts(int numHosts) {
@@ -318,8 +301,11 @@ class RdapNameserverSearchActionTest extends RdapSearchActionTestCase<RdapNamese
assertAboutJson()
.that(generateActualJsonWithName("ns1.cat.lol"))
.isEqualTo(
generateExpectedJsonForNameserver(
"ns1.cat.lol", null, "2-ROID", "v4", "1.2.3.4", "rdap_host_linked.json"));
addBoilerplate(
jsonFileBuilder()
.addNameserver("ns1.cat.lol", "2-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.4")
.load("rdap_host_linked.json")));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(1);
}
@@ -329,8 +315,11 @@ class RdapNameserverSearchActionTest extends RdapSearchActionTestCase<RdapNamese
assertAboutJson()
.that(generateActualJsonWithName("Ns1.CaT.lOl"))
.isEqualTo(
generateExpectedJsonForNameserver(
"ns1.cat.lol", null, "2-ROID", "v4", "1.2.3.4", "rdap_host_linked.json"));
addBoilerplate(
jsonFileBuilder()
.addNameserver("ns1.cat.lol", "2-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.4")
.load("rdap_host_linked.json")));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(1);
}
@@ -356,13 +345,11 @@ class RdapNameserverSearchActionTest extends RdapSearchActionTestCase<RdapNamese
assertAboutJson()
.that(generateActualJsonWithName("ns2.cat.lol"))
.isEqualTo(
generateExpectedJsonForNameserver(
"ns2.cat.lol",
null,
"4-ROID",
"v6",
"bad:f00d:cafe::15:beef",
"rdap_host_linked.json"));
addBoilerplate(
jsonFileBuilder()
.addNameserver("ns2.cat.lol", "4-ROID")
.putAll("ADDRESSTYPE", "v6", "ADDRESS", "bad:f00d:cafe::15:beef")
.load("rdap_host_linked.json")));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(1);
}
@@ -380,8 +367,10 @@ class RdapNameserverSearchActionTest extends RdapSearchActionTestCase<RdapNamese
assertAboutJson()
.that(generateActualJsonWithName("ns1.cat.external"))
.isEqualTo(
generateExpectedJsonForNameserver(
"ns1.cat.external", null, "8-ROID", null, null, "rdap_host_external.json"));
addBoilerplate(
jsonFileBuilder()
.addNameserver("ns1.cat.external", "8-ROID")
.load("rdap_host_external.json")));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(1);
}
@@ -391,13 +380,11 @@ class RdapNameserverSearchActionTest extends RdapSearchActionTestCase<RdapNamese
assertAboutJson()
.that(generateActualJsonWithName("ns1.cat.みんな"))
.isEqualTo(
generateExpectedJsonForNameserver(
"ns1.cat.みんな",
"ns1.cat.xn--q9jyb4c",
"B-ROID",
"v4",
"1.2.3.5",
"rdap_host_unicode.json"));
addBoilerplate(
jsonFileBuilder()
.addNameserver("ns1.cat.みんな", "B-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.5")
.load("rdap_host_unicode.json")));
metricWildcardType = WildcardType.NO_WILDCARD;
metricPrefixLength = 19;
assertThat(response.getStatus()).isEqualTo(200);
@@ -409,13 +396,11 @@ class RdapNameserverSearchActionTest extends RdapSearchActionTestCase<RdapNamese
assertAboutJson()
.that(generateActualJsonWithName("ns1.cat.xn--q9jyb4c"))
.isEqualTo(
generateExpectedJsonForNameserver(
"ns1.cat.みんな",
"ns1.cat.xn--q9jyb4c",
"B-ROID",
"v4",
"1.2.3.5",
"rdap_host_unicode.json"));
addBoilerplate(
jsonFileBuilder()
.addNameserver("ns1.cat.みんな", "B-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.5")
.load("rdap_host_unicode.json")));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(1);
}
@@ -425,8 +410,11 @@ class RdapNameserverSearchActionTest extends RdapSearchActionTestCase<RdapNamese
assertAboutJson()
.that(generateActualJsonWithName("ns1.cat.1.test"))
.isEqualTo(
generateExpectedJsonForNameserver(
"ns1.cat.1.test", null, "E-ROID", "v4", "1.2.3.6", "rdap_host.json"));
addBoilerplate(
jsonFileBuilder()
.addNameserver("ns1.cat.1.test", "E-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.6", "STATUS", "active")
.load("rdap_host.json")));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(1);
}
@@ -553,13 +541,11 @@ class RdapNameserverSearchActionTest extends RdapSearchActionTestCase<RdapNamese
assertAboutJson()
.that(generateActualJsonWithName("ns*.cat.lol"))
.isEqualTo(
generateExpectedJsonForNameserver(
"ns2.cat.lol",
null,
"4-ROID",
"v6",
"bad:f00d:cafe::15:beef",
"rdap_host_linked.json"));
addBoilerplate(
jsonFileBuilder()
.addNameserver("ns2.cat.lol", "4-ROID")
.putAll("ADDRESSTYPE", "v6", "ADDRESS", "bad:f00d:cafe::15:beef")
.load("rdap_host_linked.json")));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(2);
}
@@ -749,8 +735,11 @@ class RdapNameserverSearchActionTest extends RdapSearchActionTestCase<RdapNamese
assertAboutJson()
.that(generateActualJsonWithIp("1.2.3.4"))
.isEqualTo(
generateExpectedJsonForNameserver(
"ns1.cat.lol", null, "2-ROID", "v4", "1.2.3.4", "rdap_host_linked.json"));
addBoilerplate(
jsonFileBuilder()
.addNameserver("ns1.cat.lol", "2-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.4")
.load("rdap_host_linked.json")));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(1);
}

View File

@@ -45,107 +45,6 @@ class RdapTestHelper {
CONTACT
}
private static JsonObject createTosNotice(String linkBase) {
return GSON.toJsonTree(
ImmutableMap.of(
"title", "RDAP Terms of Service",
"description",
ImmutableList.of(
"By querying our Domain Database, you are agreeing to comply with these"
+ " terms so please read them carefully.",
"Any information provided is 'as is' without any guarantee of accuracy.",
"Please do not misuse the Domain Database. It is intended solely for"
+ " query-based access.",
"Don't use the Domain Database to allow, enable, or otherwise support the"
+ " transmission of mass unsolicited, commercial advertising or"
+ " solicitations.",
"Don't access our Domain Database through the use of high volume, automated"
+ " electronic processes that send queries or data to the systems of"
+ " any ICANN-accredited registrar.",
"You may only use the information contained in the Domain Database for"
+ " lawful purposes.",
"Do not compile, repackage, disseminate, or otherwise use the information"
+ " contained in the Domain Database in its entirety, or in any"
+ " substantial portion, without our prior written permission.",
"We may retain certain details about queries to our Domain Database for the"
+ " purposes of detecting and preventing misuse.",
"We reserve the right to restrict or deny your access to the database if we"
+ " suspect that you have failed to comply with these terms.",
"We reserve the right to modify this agreement at any time."),
"links",
ImmutableList.of(
ImmutableMap.of(
"rel", "self",
"href", linkBase + "help/tos",
"type", "application/rdap+json"),
ImmutableMap.of(
"rel", "alternate",
"href", "https://www.registry.tld/about/rdap/tos.html",
"type", "text/html"))))
.getAsJsonObject();
}
static void addNonDomainBoilerplateNotices(JsonObject jsonObject, String linkBase) {
if (!jsonObject.has("notices")) {
jsonObject.add("notices", new JsonArray());
}
JsonArray notices = jsonObject.getAsJsonArray("notices");
notices.add(createTosNotice(linkBase));
notices.add(
GSON.toJsonTree(
ImmutableMap.of(
"description",
ImmutableList.of(
"This response conforms to the RDAP Operational Profile for gTLD"
+ " Registries and Registrars version 1.0"))));
}
static void addDomainBoilerplateNotices(JsonObject jsonObject, String linkBase) {
if (!jsonObject.has("notices")) {
jsonObject.add("notices", new JsonArray());
}
JsonArray notices = jsonObject.getAsJsonArray("notices");
notices.add(createTosNotice(linkBase));
notices.add(
GSON.toJsonTree(
ImmutableMap.of(
"description",
ImmutableList.of(
"This response conforms to the RDAP Operational Profile for gTLD"
+ " Registries and Registrars version 1.0"))));
notices.add(
GSON.toJsonTree(
ImmutableMap.of(
"title",
"Status Codes",
"description",
ImmutableList.of(
"For more information on domain status codes, please visit"
+ " https://icann.org/epp"),
"links",
ImmutableList.of(
ImmutableMap.of(
"rel", "alternate",
"href", "https://icann.org/epp",
"type", "text/html")))));
notices.add(
GSON.toJsonTree(
ImmutableMap.of(
"title",
"RDDS Inaccuracy Complaint Form",
"description",
ImmutableList.of(
"URL of the ICANN RDDS Inaccuracy Complaint Form: https://icann.org/wicf"),
"links",
ImmutableList.of(
ImmutableMap.of(
"rel", "alternate",
"href", "https://icann.org/wicf",
"type", "text/html")))));
}
static RdapJsonFormatter getTestRdapJsonFormatter(Clock clock) {
RdapJsonFormatter rdapJsonFormatter = new RdapJsonFormatter();
rdapJsonFormatter.rdapAuthorization = RdapAuthorization.PUBLIC_AUTHORIZATION;
@@ -174,7 +73,7 @@ class RdapTestHelper {
"We reserve the right to restrict or deny your access to the database if we"
+ " suspect that you have failed to comply with these terms.",
"We reserve the right to modify this agreement at any time.");
rdapJsonFormatter.rdapTosStaticUrl = "https://www.registry.tld/about/rdap/tos.html";
rdapJsonFormatter.rdapTosStaticUrl = "https://www.example.tld/about/rdap/tos.html";
return rdapJsonFormatter;
}

View File

@@ -25,6 +25,7 @@ import google.registry.model.common.CursorTest;
import google.registry.model.common.DnsRefreshRequestTest;
import google.registry.model.common.FeatureFlagTest;
import google.registry.model.console.ConsoleUpdateHistoryTest;
import google.registry.model.console.PasswordResetRequestTest;
import google.registry.model.console.UserTest;
import google.registry.model.contact.ContactTest;
import google.registry.model.domain.DomainSqlTest;
@@ -104,6 +105,7 @@ import org.junit.runner.RunWith;
FeatureFlagTest.class,
HostHistoryTest.class,
LockTest.class,
PasswordResetRequestTest.class,
PollMessageTest.class,
PremiumListDaoTest.class,
RdeRevisionTest.class,

View File

@@ -15,10 +15,10 @@
package google.registry.schema.registrar;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
import static google.registry.model.registrar.RegistrarPoc.Type.WHOIS;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.testing.DatabaseHelper.insertInDb;
import static google.registry.testing.DatabaseHelper.loadByEntity;
import static google.registry.testing.SqlHelper.saveRegistrar;
import com.google.common.collect.ImmutableSet;
@@ -63,7 +63,9 @@ class RegistrarPocTest {
@Test
void testPersistence_succeeds() {
insertInDb(testRegistrarPoc);
assertThat(loadByEntity(testRegistrarPoc)).isEqualTo(testRegistrarPoc);
assertAboutImmutableObjects()
.that(testRegistrarPoc)
.isEqualExceptFields(testRegistrarPoc, "id");
}
@Test

View File

@@ -15,6 +15,7 @@
package google.registry.tools;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
import static google.registry.model.registrar.RegistrarPoc.Type.ABUSE;
import static google.registry.model.registrar.RegistrarPoc.Type.ADMIN;
import static google.registry.model.registrar.RegistrarPoc.Type.TECH;
@@ -102,8 +103,9 @@ class RegistrarPocCommandTest extends CommandTestCase<RegistrarPocCommand> {
"--visible_in_domain_whois_as_abuse=false",
"NewRegistrar");
RegistrarPoc registrarPoc = loadRegistrar("NewRegistrar").getContacts().asList().get(1);
assertThat(registrarPoc)
.isEqualTo(
assertAboutImmutableObjects()
.that(registrarPoc)
.isEqualExceptFields(
new RegistrarPoc.Builder()
.setRegistrar(registrar)
.setName("Judith Registrar")
@@ -115,7 +117,8 @@ class RegistrarPocCommandTest extends CommandTestCase<RegistrarPocCommand> {
.setVisibleInWhoisAsAdmin(true)
.setVisibleInWhoisAsTech(false)
.setVisibleInDomainWhoisAsAbuse(false)
.build());
.build(),
"id");
}
@Test
@@ -261,8 +264,9 @@ class RegistrarPocCommandTest extends CommandTestCase<RegistrarPocCommand> {
"--visible_in_domain_whois_as_abuse=true",
"NewRegistrar");
RegistrarPoc registrarPoc = loadRegistrar("NewRegistrar").getContacts().asList().get(1);
assertThat(registrarPoc)
.isEqualTo(
assertAboutImmutableObjects()
.that(registrarPoc)
.isEqualExceptFields(
new RegistrarPoc.Builder()
.setRegistrar(registrar)
.setName("Jim Doe")
@@ -272,7 +276,8 @@ class RegistrarPocCommandTest extends CommandTestCase<RegistrarPocCommand> {
.setVisibleInWhoisAsAdmin(true)
.setVisibleInWhoisAsTech(false)
.setVisibleInDomainWhoisAsAbuse(true)
.build());
.build(),
"id");
}
@Test

View File

@@ -20,8 +20,10 @@ import static google.registry.model.registrar.RegistrarPoc.Type.ABUSE;
import static google.registry.model.registrar.RegistrarPoc.Type.ADMIN;
import static google.registry.model.registrar.RegistrarPoc.Type.MARKETING;
import static google.registry.model.registrar.RegistrarPoc.Type.TECH;
import static google.registry.testing.DatabaseHelper.deleteResource;
import static google.registry.testing.DatabaseHelper.insertInDb;
import static google.registry.testing.DatabaseHelper.loadAllOf;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.testing.SqlHelper.saveRegistrar;
import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN;
@@ -57,7 +59,7 @@ import org.junit.jupiter.api.Test;
/** Tests for {@link google.registry.ui.server.console.settings.ContactAction}. */
class ContactActionTest extends ConsoleActionBaseTestCase {
private static String jsonRegistrar1 =
"{\"name\":\"Test Registrar 1\","
"{\"id\":%s,\"name\":\"Test Registrar 1\","
+ "\"emailAddress\":\"test.registrar1@example.com\","
+ "\"registrarId\":\"registrarId\","
+ "\"phoneNumber\":\"+1.9999999999\",\"faxNumber\":\"+1.9999999991\","
@@ -73,17 +75,18 @@ class ContactActionTest extends ConsoleActionBaseTestCase {
void beforeEach() {
testRegistrar = saveRegistrar("registrarId");
adminPoc =
new RegistrarPoc.Builder()
.setRegistrar(testRegistrar)
.setName("Test Registrar 1")
.setEmailAddress("test.registrar1@example.com")
.setPhoneNumber("+1.9999999999")
.setFaxNumber("+1.9999999991")
.setTypes(ImmutableSet.of(ADMIN))
.setVisibleInWhoisAsAdmin(true)
.setVisibleInWhoisAsTech(false)
.setVisibleInDomainWhoisAsAbuse(false)
.build();
persistResource(
new RegistrarPoc.Builder()
.setRegistrar(testRegistrar)
.setName("Test Registrar 1")
.setEmailAddress("test.registrar1@example.com")
.setPhoneNumber("+1.9999999999")
.setFaxNumber("+1.9999999991")
.setTypes(ImmutableSet.of(ADMIN))
.setVisibleInWhoisAsAdmin(true)
.setVisibleInWhoisAsTech(false)
.setVisibleInDomainWhoisAsAbuse(false)
.build());
techPoc =
adminPoc
.asBuilder()
@@ -109,39 +112,26 @@ class ContactActionTest extends ConsoleActionBaseTestCase {
@Test
void testSuccess_getContactInfo() throws IOException {
insertInDb(adminPoc);
ContactAction action = createAction(Action.Method.GET, fteUser, testRegistrar.getRegistrarId());
ContactAction action =
createAction(Action.Method.GET, fteUser, testRegistrar.getRegistrarId(), null);
action.run();
assertThat(response.getStatus()).isEqualTo(SC_OK);
assertThat(response.getPayload()).isEqualTo("[" + jsonRegistrar1 + "]");
assertThat(response.getPayload()).contains(String.format(jsonRegistrar1, adminPoc.getId()));
}
@Test
void testSuccess_noOp() throws IOException {
insertInDb(adminPoc);
ContactAction action =
createAction(Action.Method.POST, fteUser, testRegistrar.getRegistrarId(), adminPoc);
createAction(Action.Method.PUT, fteUser, testRegistrar.getRegistrarId(), adminPoc);
action.run();
assertThat(response.getStatus()).isEqualTo(SC_OK);
verify(consoleApiParams.sendEmailUtils().gmailClient, never()).sendEmail(any());
}
@Test
void testSuccess_onlyContactsWithNonEmptyType() throws IOException {
adminPoc = adminPoc.asBuilder().setTypes(ImmutableSet.of()).build();
insertInDb(adminPoc);
ContactAction action = createAction(Action.Method.GET, fteUser, testRegistrar.getRegistrarId());
action.run();
assertThat(response.getStatus()).isEqualTo(SC_OK);
assertThat(response.getPayload()).isEqualTo("[]");
}
@Test
void testSuccess_postCreateContactInfo() throws IOException {
insertInDb(adminPoc);
ContactAction action =
createAction(
Action.Method.POST, fteUser, testRegistrar.getRegistrarId(), adminPoc, techPoc);
createAction(Action.Method.POST, fteUser, testRegistrar.getRegistrarId(), techPoc);
action.run();
assertThat(response.getStatus()).isEqualTo(SC_OK);
assertThat(
@@ -154,10 +144,14 @@ class ContactActionTest extends ConsoleActionBaseTestCase {
@Test
void testSuccess_postUpdateContactInfo() throws IOException {
insertInDb(techPoc.asBuilder().setEmailAddress("incorrect@email.com").build());
RegistrarPoc techPocIncorrect =
persistResource(techPoc.asBuilder().setEmailAddress("incorrect@email.com").build());
ContactAction action =
createAction(
Action.Method.POST, fteUser, testRegistrar.getRegistrarId(), adminPoc, techPoc);
Action.Method.PUT,
fteUser,
testRegistrar.getRegistrarId(),
techPocIncorrect.asBuilder().setEmailAddress(techPoc.getEmailAddress()).build());
action.run();
assertThat(response.getStatus()).isEqualTo(SC_OK);
HashMap<String, String> testResult = new HashMap<>();
@@ -174,12 +168,12 @@ class ContactActionTest extends ConsoleActionBaseTestCase {
@Test
void testFailure_postUpdateContactInfo_duplicateEmails() throws IOException {
insertInDb(techPoc);
ContactAction action =
createAction(
Action.Method.POST,
fteUser,
testRegistrar.getRegistrarId(),
adminPoc,
techPoc.asBuilder().setEmailAddress("test.registrar1@example.com").build());
action.run();
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
@@ -189,16 +183,16 @@ class ContactActionTest extends ConsoleActionBaseTestCase {
assertThat(
loadAllOf(RegistrarPoc.class).stream()
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
.map(r -> r.getName())
.collect(toImmutableList()))
.isEmpty();
.containsExactly("Test Registrar 1", "Test Registrar 2");
}
@Test
void testFailure_postUpdateContactInfo_requiredContactRemoved() throws IOException {
insertInDb(adminPoc);
ContactAction action =
createAction(
Action.Method.POST,
Action.Method.PUT,
fteUser,
testRegistrar.getRegistrarId(),
adminPoc.asBuilder().setTypes(ImmutableSet.of(ABUSE)).build());
@@ -214,11 +208,10 @@ class ContactActionTest extends ConsoleActionBaseTestCase {
@Test
void testFailure_postUpdateContactInfo_phoneNumberRemoved() throws IOException {
adminPoc = adminPoc.asBuilder().setTypes(ImmutableSet.of(ADMIN, TECH)).build();
insertInDb(adminPoc);
adminPoc = persistResource(adminPoc.asBuilder().setTypes(ImmutableSet.of(ADMIN, TECH)).build());
ContactAction action =
createAction(
Action.Method.POST,
Action.Method.PUT,
fteUser,
testRegistrar.getRegistrarId(),
adminPoc
@@ -244,25 +237,19 @@ class ContactActionTest extends ConsoleActionBaseTestCase {
Action.Method.POST,
fteUser,
testRegistrar.getRegistrarId(),
adminPoc.asBuilder().setPhoneNumber(null).setVisibleInDomainWhoisAsAbuse(true).build());
techPoc.asBuilder().setPhoneNumber(null).setVisibleInDomainWhoisAsAbuse(true).build());
action.run();
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload())
.isEqualTo("The abuse contact visible in domain WHOIS query must have a phone number");
assertThat(
loadAllOf(RegistrarPoc.class).stream()
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
.collect(toImmutableList()))
.isEmpty();
}
@Test
void testFailure_postUpdateContactInfo_whoisContactPhoneNumberRemoved() throws IOException {
adminPoc = adminPoc.asBuilder().setVisibleInDomainWhoisAsAbuse(true).build();
insertInDb(adminPoc);
adminPoc = persistResource(adminPoc.asBuilder().setVisibleInDomainWhoisAsAbuse(true).build());
ContactAction action =
createAction(
Action.Method.POST,
Action.Method.PUT,
fteUser,
testRegistrar.getRegistrarId(),
adminPoc.asBuilder().setVisibleInDomainWhoisAsAbuse(false).build());
@@ -277,88 +264,17 @@ class ContactActionTest extends ConsoleActionBaseTestCase {
.containsExactly(adminPoc);
}
@Test
void testFailure_postUpdateContactInfo_newContactCannotSetRegistryLockPassword()
throws IOException {
ContactAction action =
createAction(
Action.Method.POST,
fteUser,
testRegistrar.getRegistrarId(),
adminPoc
.asBuilder()
.setAllowedToSetRegistryLockPassword(true)
.setRegistryLockEmailAddress("lock@example.com")
.build());
action.run();
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload())
.isEqualTo("Cannot set registry lock password directly on new contact");
assertThat(
loadAllOf(RegistrarPoc.class).stream()
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
.collect(toImmutableList()))
.isEmpty();
}
@Test
void testFailure_postUpdateContactInfo_cannotModifyRegistryLockEmail() throws IOException {
adminPoc =
adminPoc
.asBuilder()
.setRegistryLockEmailAddress("lock@example.com")
.setAllowedToSetRegistryLockPassword(true)
.build();
insertInDb(adminPoc);
ContactAction action =
createAction(
Action.Method.POST,
fteUser,
testRegistrar.getRegistrarId(),
adminPoc.asBuilder().setRegistryLockEmailAddress("unlock@example.com").build());
action.run();
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload())
.isEqualTo("Cannot modify registryLockEmailAddress through the UI");
assertThat(
loadAllOf(RegistrarPoc.class).stream()
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
.collect(toImmutableList()))
.containsExactly(adminPoc);
}
@Test
void testFailure_postUpdateContactInfo_cannotSetIsAllowedToSetRegistryLockPassword()
throws IOException {
adminPoc =
adminPoc
.asBuilder()
.setRegistryLockEmailAddress("lock@example.com")
.setAllowedToSetRegistryLockPassword(false)
.build();
insertInDb(adminPoc);
ContactAction action =
createAction(
Action.Method.POST,
fteUser,
testRegistrar.getRegistrarId(),
adminPoc.asBuilder().setAllowedToSetRegistryLockPassword(true).build());
action.run();
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload())
.isEqualTo("Cannot modify isAllowedToSetRegistryLockPassword through the UI");
assertThat(
loadAllOf(RegistrarPoc.class).stream()
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
.collect(toImmutableList()))
.containsExactly(adminPoc);
}
@Test
void testSuccess_sendsEmail() throws IOException, AddressException {
insertInDb(techPoc.asBuilder().setEmailAddress("incorrect@email.com").build());
deleteResource(adminPoc);
techPoc = persistResource(techPoc);
Long id = techPoc.getId();
ContactAction action =
createAction(Action.Method.POST, fteUser, testRegistrar.getRegistrarId(), techPoc);
createAction(
Action.Method.PUT,
fteUser,
testRegistrar.getRegistrarId(),
techPoc.asBuilder().setEmailAddress("incorrect@example.com").build());
action.run();
assertThat(response.getStatus()).isEqualTo(SC_OK);
verify(consoleApiParams.sendEmailUtils().gmailClient, times(1))
@@ -373,23 +289,29 @@ class ContactActionTest extends ConsoleActionBaseTestCase {
+ "\n"
+ "contacts:\n"
+ " ADDED:\n"
+ " {name=Test Registrar 2,"
+ " emailAddress=test.registrar2@example.com, registrarId=registrarId,"
+ " {id="
+ id
+ ", name=Test Registrar 2,"
+ " emailAddress=incorrect@example.com, registrarId=registrarId,"
+ " registryLockEmailAddress=null, phoneNumber=+1.1234567890,"
+ " faxNumber=+1.1234567891, types=[TECH],"
+ " visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=true,"
+ " visibleInDomainWhoisAsAbuse=false,"
+ " allowedToSetRegistryLockPassword=false}\n"
+ " REMOVED:\n"
+ " {name=Test Registrar 2, emailAddress=incorrect@email.com,"
+ " {id="
+ id
+ ", name=Test Registrar 2, emailAddress=test.registrar2@example.com,"
+ " registrarId=registrarId, registryLockEmailAddress=null,"
+ " phoneNumber=+1.1234567890, faxNumber=+1.1234567891, types=[TECH],"
+ " visibleInWhoisAsAdmin=false,"
+ " visibleInWhoisAsTech=true, visibleInDomainWhoisAsAbuse=false,"
+ " allowedToSetRegistryLockPassword=false}\n"
+ " FINAL CONTENTS:\n"
+ " {name=Test Registrar 2,"
+ " emailAddress=test.registrar2@example.com, registrarId=registrarId,"
+ " {id="
+ id
+ ", name=Test Registrar 2,"
+ " emailAddress=incorrect@example.com, registrarId=registrarId,"
+ " registryLockEmailAddress=null, phoneNumber=+1.1234567890,"
+ " faxNumber=+1.1234567891, types=[TECH],"
+ " visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=true,"
@@ -401,10 +323,9 @@ class ContactActionTest extends ConsoleActionBaseTestCase {
@Test
void testSuccess_postDeleteContactInfo() throws IOException {
insertInDb(adminPoc, techPoc, marketingPoc);
insertInDb(techPoc, marketingPoc);
ContactAction action =
createAction(
Action.Method.POST, fteUser, testRegistrar.getRegistrarId(), adminPoc, techPoc);
createAction(Action.Method.DELETE, fteUser, testRegistrar.getRegistrarId(), marketingPoc);
action.run();
assertThat(response.getStatus()).isEqualTo(SC_OK);
assertThat(
@@ -417,10 +338,9 @@ class ContactActionTest extends ConsoleActionBaseTestCase {
@Test
void testFailure_postDeleteContactInfo_missingPermission() throws IOException {
insertInDb(adminPoc);
ContactAction action =
createAction(
Action.Method.POST,
Action.Method.DELETE,
new User.Builder()
.setEmailAddress("email@email.com")
.setUserRoles(
@@ -438,9 +358,12 @@ class ContactActionTest extends ConsoleActionBaseTestCase {
@Test
void testFailure_changesAdminEmail() throws Exception {
insertInDb(adminPoc.asBuilder().setEmailAddress("oldemail@example.com").build());
ContactAction action =
createAction(Action.Method.POST, fteUser, testRegistrar.getRegistrarId(), adminPoc);
createAction(
Action.Method.PUT,
fteUser,
testRegistrar.getRegistrarId(),
adminPoc.asBuilder().setEmailAddress("testemail@example.com").build());
action.run();
FakeResponse fakeResponse = response;
assertThat(fakeResponse.getStatus()).isEqualTo(400);
@@ -449,16 +372,14 @@ class ContactActionTest extends ConsoleActionBaseTestCase {
}
private ContactAction createAction(
Action.Method method, User user, String registrarId, RegistrarPoc... contacts)
Action.Method method, User user, String registrarId, RegistrarPoc contact)
throws IOException {
consoleApiParams = ConsoleApiParamsUtils.createFake(AuthResult.createUser(user));
when(consoleApiParams.request().getMethod()).thenReturn(method.toString());
response = (FakeResponse) consoleApiParams.response();
if (method.equals(Action.Method.GET)) {
return new ContactAction(consoleApiParams, registrarId, Optional.empty());
} else {
return new ContactAction(
consoleApiParams, registrarId, Optional.of(ImmutableSet.copyOf(contacts)));
}
return new ContactAction(consoleApiParams, registrarId, Optional.of(contact));
}
}

View File

@@ -16,7 +16,7 @@ package google.registry.whois;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.bsa.persistence.BsaTestingUtils.persistBsaLabel;
import static google.registry.model.EppResourceUtils.loadByForeignKeyCached;
import static google.registry.model.EppResourceUtils.loadByForeignKeyByCacheIfEnabled;
import static google.registry.model.registrar.Registrar.State.ACTIVE;
import static google.registry.model.registrar.Registrar.Type.PDT;
import static google.registry.model.tld.Tlds.getTlds;
@@ -147,8 +147,9 @@ public class WhoisActionTest {
persistResource(makeDomainWithRegistrar(registrar));
persistSimpleResources(makeRegistrarPocs(registrar));
// Populate the cache for both the domain and contact.
Domain domain = loadByForeignKeyCached(Domain.class, "cat.lol", clock.nowUtc()).get();
Contact contact = loadByForeignKeyCached(Contact.class, "5372808-ERL", clock.nowUtc()).get();
Domain domain = loadByForeignKeyByCacheIfEnabled(Domain.class, "cat.lol", clock.nowUtc()).get();
Contact contact =
loadByForeignKeyByCacheIfEnabled(Contact.class, "5372808-ERL", clock.nowUtc()).get();
// Make a change to the domain and contact that won't be seen because the cache will be hit.
persistResource(domain.asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
persistResource(
@@ -280,7 +281,7 @@ public class WhoisActionTest {
@Test
void testRun_domainNotFound_usesCache() {
// Populate the cache with the nonexistence of this domain.
assertThat(loadByForeignKeyCached(Domain.class, "cat.lol", clock.nowUtc())).isEmpty();
assertThat(loadByForeignKeyByCacheIfEnabled(Domain.class, "cat.lol", clock.nowUtc())).isEmpty();
// Add a new valid cat.lol domain that won't be found because the cache will be hit instead.
persistActiveDomain("cat.lol");
newWhoisAction("domain cat.lol\r\n").run();
@@ -435,7 +436,8 @@ public class WhoisActionTest {
void testRun_nameserver_usesCache() {
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.xn--q9jyb4c", "1.2.3.4"));
// Populate the cache.
Host host = loadByForeignKeyCached(Host.class, "ns1.cat.xn--q9jyb4c", clock.nowUtc()).get();
Host host =
loadByForeignKeyByCacheIfEnabled(Host.class, "ns1.cat.xn--q9jyb4c", clock.nowUtc()).get();
// Make a change to the persisted host that won't be seen because the cache will be hit.
persistResource(
host.asBuilder()

View File

@@ -11,7 +11,7 @@ CONSOLE /console-api/registrar ConsoleUpdateRegistrarAction POST
CONSOLE /console-api/registrars RegistrarsAction GET,POST n USER PUBLIC
CONSOLE /console-api/registry-lock ConsoleRegistryLockAction GET,POST n USER PUBLIC
CONSOLE /console-api/registry-lock-verify ConsoleRegistryLockVerifyAction GET n USER PUBLIC
CONSOLE /console-api/settings/contacts ContactAction GET,POST n USER PUBLIC
CONSOLE /console-api/settings/contacts ContactAction GET,POST,DELETE,PUT n USER PUBLIC
CONSOLE /console-api/settings/rdap-fields RdapRegistrarFieldsAction POST n USER PUBLIC
CONSOLE /console-api/settings/security SecurityAction POST n USER PUBLIC
CONSOLE /console-api/userdata ConsoleUserDataAction GET n USER PUBLIC

View File

@@ -79,7 +79,7 @@ CONSOLE /console-api/registrar ConsoleUpdateRegistr
CONSOLE /console-api/registrars RegistrarsAction GET,POST n USER PUBLIC
CONSOLE /console-api/registry-lock ConsoleRegistryLockAction GET,POST n USER PUBLIC
CONSOLE /console-api/registry-lock-verify ConsoleRegistryLockVerifyAction GET n USER PUBLIC
CONSOLE /console-api/settings/contacts ContactAction GET,POST n USER PUBLIC
CONSOLE /console-api/settings/contacts ContactAction GET,POST,DELETE,PUT n USER PUBLIC
CONSOLE /console-api/settings/rdap-fields RdapRegistrarFieldsAction POST n USER PUBLIC
CONSOLE /console-api/settings/security SecurityAction POST n USER PUBLIC
CONSOLE /console-api/userdata ConsoleUserDataAction GET n USER PUBLIC

View File

@@ -5,13 +5,14 @@
"icann_rdap_technical_implementation_guide_0"
],
"objectClassName": "entity",
"handle": "%NAME%",
"handle": "%CONTACT_HANDLE_1%",
"status": ["active", "associated"],
"links": [
{
"rel": "self",
"href": "https://example.tld/rdap/entity/%NAME%",
"type": "application/rdap+json"
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_1%",
"type": "application/rdap+json",
"value": "%REQUEST_URL%"
}
],
"events": [
@@ -25,13 +26,13 @@
"vcard",
[
["version", {}, "text", "4.0"],
["fn", {}, "text", "%FULLNAME%"],
["fn", {}, "text", "%CONTACT_FULLNAME_1%"],
["org", {}, "text", "GOOGLE INCORPORATED <script>"],
["adr", {}, "text",
[
"",
"",
[ %ADDRESS% ],
[ %CONTACT_ADDRESS_1% ],
"KOKOMO",
"BM",
"31337",

View File

@@ -27,7 +27,8 @@
{
"type":"text\/html",
"href": "https:\/\/github.com\/google\/nomulus\/blob\/master\/docs\/rdap.md#authentication",
"rel": "alternate"
"rel": "alternate",
"value": "%REQUEST_URL%"
}
],
"description": [

View File

@@ -5,14 +5,15 @@
"icann_rdap_technical_implementation_guide_0"
],
"objectClassName" : "entity",
"handle" : "%NAME%",
"status" : ["%STATUS%"],
"handle" : "%CONTACT_HANDLE_1%",
"status" : ["%STATUS_1%"],
"links" :
[
{
"rel" : "self",
"href": "https://example.tld/rdap/entity/%NAME%",
"type" : "application/rdap+json"
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_1%",
"type" : "application/rdap+json",
"value": "%REQUEST_URL%"
}
],
"events": [
@@ -26,13 +27,13 @@
"vcard",
[
["version", {}, "text", "4.0"],
["fn", {}, "text", "%FULLNAME%"],
["fn", {}, "text", "%CONTACT_FULLNAME_1%"],
["org", {}, "text", "GOOGLE INCORPORATED <script>"],
["adr", {}, "text",
[
"",
"",
[ %ADDRESS% ],
[ %CONTACT_ADDRESS_1% ],
"KOKOMO",
"BM",
"31337",

View File

@@ -5,14 +5,15 @@
"icann_rdap_technical_implementation_guide_0"
],
"objectClassName" : "entity",
"handle" : "%NAME%",
"handle" : "%CONTACT_HANDLE_1%",
"status" : ["inactive"],
"links" :
[
{
"rel" : "self",
"href": "https://example.tld/rdap/entity/%NAME%",
"type" : "application/rdap+json"
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_1%",
"type" : "application/rdap+json",
"value": "%REQUEST_URL%"
}
],
"events":
@@ -38,5 +39,4 @@
]
}
]
}

View File

@@ -32,7 +32,8 @@
{
"rel" : "alternate",
"href" : "https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"type" : "text/html"
"type" : "text/html",
"value": "https://example.tld/rdap/entities"
}
]
},

View File

@@ -17,17 +17,20 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
},
{
"href": "https://rdap.example.com/withSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "%REQUEST_URL%"
},
{
"href": "https://rdap.example.com/withoutSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "%REQUEST_URL%"
}
],
"events": [
@@ -58,7 +61,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"remarks": [
@@ -79,7 +83,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"remarks": [
@@ -115,7 +120,8 @@
{
"href": "https://example.tld/rdap/entity/1",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray" : [
@@ -160,7 +166,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [
@@ -197,7 +204,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [
@@ -236,7 +244,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_3%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [

View File

@@ -13,7 +13,8 @@
{
"href": "https://example.tld/rdap/entity/1",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/addgraceperiod.lol"
}
],
"publicIds": [
@@ -65,7 +66,8 @@
{
"href": "https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel": "alternate",
"type": "text/html"
"type": "text/html",
"value": "https://example.tld/rdap/domain/addgraceperiod.lol"
}
],
"title": "REDACTED FOR PRIVACY",
@@ -124,7 +126,8 @@
{
"href": "https://example.tld/rdap/domain/addgraceperiod.lol",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/addgraceperiod.lol"
}
],
"nameservers": [
@@ -136,7 +139,8 @@
{
"href": "https://example.tld/rdap/nameserver/ns1.cat.lol",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/addgraceperiod.lol"
}
],
"remarks": [

View File

@@ -13,7 +13,8 @@
{
"href": "https://example.tld/rdap/entity/1",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/autorenew.lol"
}
],
"publicIds": [
@@ -65,7 +66,8 @@
{
"href": "https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel": "alternate",
"type": "text/html"
"type": "text/html",
"value": "https://example.tld/rdap/domain/autorenew.lol"
}
],
"title": "REDACTED FOR PRIVACY",
@@ -128,7 +130,8 @@
{
"href": "https://example.tld/rdap/domain/autorenew.lol",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/autorenew.lol"
}
],
"nameservers": [
@@ -140,7 +143,8 @@
{
"href": "https://example.tld/rdap/nameserver/ns1.cat.lol",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/autorenew.lol"
}
],
"remarks": [

View File

@@ -17,17 +17,20 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
},
{
"href": "https://rdap.example.com/withSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "https://example.tld/rdap/domains"
},
{
"href": "https://rdap.example.com/withoutSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "https://example.tld/rdap/domains"
}
],
"events": [
@@ -58,7 +61,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -77,7 +81,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -98,7 +103,8 @@
{
"href": "https://example.tld/rdap/entity/1",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"vcardArray" : [
@@ -149,7 +155,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [
@@ -186,7 +193,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [
@@ -223,7 +231,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_3%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [

View File

@@ -18,17 +18,20 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
},
{
"href": "https://rdap.example.com/withSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "%REQUEST_URL%"
},
{
"href": "https://rdap.example.com/withoutSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "%REQUEST_URL%"
}
],
"events": [
@@ -64,7 +67,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"remarks": [
@@ -83,7 +87,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"remarks": [
@@ -110,7 +115,8 @@
{
"href": "https://example.tld/rdap/entity/1",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray" : [
@@ -155,7 +161,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [
@@ -192,7 +199,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [
@@ -229,7 +237,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_3%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [

View File

@@ -13,7 +13,8 @@
{
"href": "https://example.tld/rdap/entity/1",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/renew.lol"
}
],
"publicIds": [
@@ -65,7 +66,8 @@
{
"href": "https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel": "alternate",
"type": "text/html"
"type": "text/html",
"value": "https://example.tld/rdap/domain/renew.lol"
}
],
"title": "REDACTED FOR PRIVACY",
@@ -124,7 +126,8 @@
{
"href": "https://example.tld/rdap/domain/renew.lol",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/renew.lol"
}
],
"nameservers": [
@@ -136,7 +139,8 @@
{
"href": "https://example.tld/rdap/nameserver/ns1.cat.lol",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/renew.lol"
}
],
"remarks": [

View File

@@ -17,17 +17,20 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domain/cat.lol"
},
{
"href": "https://rdap.example.com/withSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "https://example.tld/rdap/domain/cat.lol"
},
{
"href": "https://rdap.example.com/withoutSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "https://example.tld/rdap/domain/cat.lol"
}
],
"events": [
@@ -58,7 +61,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domain/cat.lol"
}
],
"remarks": [
@@ -77,7 +81,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domain/cat.lol"
}
],
"remarks": [
@@ -105,7 +110,8 @@
{
"rel" : "self",
"href" : "https://example.tld/rdap/entity/1",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "https://example.tld/rdap/domain/cat.lol"
}
],
"publicIds" : [

View File

@@ -17,17 +17,20 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domain/cat.lol"
},
{
"href": "https://rdap.example.com/withSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "https://example.tld/rdap/domain/cat.lol"
},
{
"href": "https://rdap.example.com/withoutSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "https://example.tld/rdap/domain/cat.lol"
}
],
"events": [
@@ -58,7 +61,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domain/cat.lol"
}
],
"remarks": [
@@ -77,7 +81,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domain/cat.lol"
}
],
"remarks": [
@@ -105,7 +110,8 @@
{
"rel" : "self",
"href" : "https://example.tld/rdap/entity/1",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "https://example.tld/rdap/domain/cat.lol"
}
],
"publicIds" : [
@@ -164,7 +170,8 @@
{
"href":"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel":"alternate",
"type":"text/html"
"type":"text/html",
"value": "https://example.tld/rdap/domain/cat.lol"
}
]
},
@@ -200,7 +207,8 @@
{
"href":"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel":"alternate",
"type":"text/html"
"type":"text/html",
"value": "https://example.tld/rdap/domain/cat.lol"
}
]
},

View File

@@ -13,7 +13,8 @@
{
"href": "https://example.tld/rdap/entity/1",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/redemption.lol"
}
],
"publicIds": [
@@ -65,7 +66,8 @@
{
"href": "https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel": "alternate",
"type": "text/html"
"type": "text/html",
"value": "https://example.tld/rdap/domain/redemption.lol"
}
],
"title": "REDACTED FOR PRIVACY",
@@ -124,7 +126,8 @@
{
"href": "https://example.tld/rdap/domain/redemption.lol",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/redemption.lol"
}
],
"nameservers": [
@@ -136,7 +139,8 @@
{
"href": "https://example.tld/rdap/nameserver/ns1.cat.lol",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/redemption.lol"
}
],
"remarks": [

View File

@@ -17,17 +17,20 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
},
{
"href": "https://rdap.example.com/withSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "%REQUEST_URL%"
},
{
"href": "https://rdap.example.com/withoutSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "%REQUEST_URL%"
}
],
"events": [
@@ -58,7 +61,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"remarks": [
@@ -77,7 +81,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"remarks": [
@@ -105,7 +110,8 @@
{
"rel" : "self",
"href" : "https://example.tld/rdap/entity/1",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "%REQUEST_URL%"
}
],
"publicIds" : [
@@ -164,7 +170,8 @@
{
"href":"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel":"alternate",
"type":"text/html"
"type":"text/html",
"value": "%REQUEST_URL%"
}
]
},
@@ -200,7 +207,8 @@
{
"href":"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel":"alternate",
"type":"text/html"
"type":"text/html",
"value": "%REQUEST_URL%"
}
]
},
@@ -237,7 +245,8 @@
{
"href":"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel":"alternate",
"type":"text/html"
"type":"text/html",
"value": "%REQUEST_URL%"
}
]
},

View File

@@ -13,7 +13,8 @@
{
"href": "https://example.tld/rdap/entity/1",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/transfer.lol"
}
],
"publicIds": [
@@ -65,7 +66,8 @@
{
"href": "https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel": "alternate",
"type": "text/html"
"type": "text/html",
"value": "https://example.tld/rdap/domain/transfer.lol"
}
],
"title": "REDACTED FOR PRIVACY",
@@ -124,7 +126,8 @@
{
"href": "https://example.tld/rdap/domain/transfer.lol",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/transfer.lol"
}
],
"nameservers": [
@@ -136,7 +139,8 @@
{
"href": "https://example.tld/rdap/nameserver/ns1.cat.lol",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/transfer.lol"
}
],
"remarks": [

View File

@@ -18,17 +18,20 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
},
{
"href": "https://rdap.example.com/withSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "%REQUEST_URL%"
},
{
"href": "https://rdap.example.com/withoutSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "%REQUEST_URL%"
}
],
"events": [
@@ -60,7 +63,8 @@
"href":
"https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"remarks": [
@@ -80,7 +84,8 @@
"href":
"https://example.tld/rdap/nameserver/%NAMESERVER_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"remarks": [
@@ -108,7 +113,8 @@
{
"href": "https://example.tld/rdap/entity/1",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray" : [
@@ -159,7 +165,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [
@@ -196,7 +203,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [
@@ -233,7 +241,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_3%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [

View File

@@ -18,17 +18,20 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
},
{
"href": "https://rdap.example.com/withSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "https://example.tld/rdap/domains"
},
{
"href": "https://rdap.example.com/withoutSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "https://example.tld/rdap/domains"
}
],
"events": [
@@ -60,7 +63,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -80,7 +84,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -108,7 +113,8 @@
{
"rel" : "self",
"href" : "https://example.tld/rdap/entity/1",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "https://example.tld/rdap/domains"
}
],
"publicIds" : [
@@ -167,7 +173,8 @@
{
"href":"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel":"alternate",
"type":"text/html"
"type":"text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -203,7 +210,8 @@
{
"href":"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel":"alternate",
"type":"text/html"
"type":"text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -239,7 +247,8 @@
{
"href":"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel":"alternate",
"type":"text/html"
"type":"text/html",
"value": "https://example.tld/rdap/domains"
}
]
},

View File

@@ -8,7 +8,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -27,7 +28,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -46,7 +48,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_3%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -65,7 +68,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_4%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -100,7 +104,8 @@
{
"type" : "application/rdap+json",
"rel" : "next",
"href" : "https://example.tld/rdap/domains?%NEXT_QUERY%"
"href" : "https://example.tld/rdap/domains?%NEXT_QUERY%",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -124,12 +129,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domains"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -148,9 +155,10 @@
"links" :
[
{
"rel" : "alternate",
"rel" : "glossary",
"href" : "https://icann.org/epp",
"type" : "text/html"
"type" : "text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -160,9 +168,10 @@
"links" :
[
{
"rel" : "alternate",
"rel" : "help",
"href" : "https://icann.org/wicf",
"type" : "text/html"
"type" : "text/html",
"value": "https://example.tld/rdap/domains"
}
]
}

View File

@@ -8,7 +8,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -27,7 +28,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -46,7 +48,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_3%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -66,7 +69,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_4%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -105,12 +109,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domains"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -129,9 +135,10 @@
"links" :
[
{
"rel" : "alternate",
"rel" : "glossary",
"href" : "https://icann.org/epp",
"type" : "text/html"
"type" : "text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -141,9 +148,10 @@
"links" :
[
{
"rel" : "alternate",
"rel" : "help",
"href" : "https://icann.org/wicf",
"type" : "text/html"
"type" : "text/html",
"value": "https://example.tld/rdap/domains"
}
]
}

View File

@@ -8,7 +8,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -27,7 +28,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -46,7 +48,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_3%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -66,7 +69,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_4%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -101,7 +105,8 @@
{
"type" : "application/rdap+json",
"rel" : "next",
"href" : "https://example.tld/rdap/domains?%NEXT_QUERY%"
"href" : "https://example.tld/rdap/domains?%NEXT_QUERY%",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -125,12 +130,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domains"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -149,9 +156,10 @@
"links" :
[
{
"rel" : "alternate",
"rel" : "glossary",
"href" : "https://icann.org/epp",
"type" : "text/html"
"type" : "text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -161,9 +169,10 @@
"links" :
[
{
"rel" : "alternate",
"rel" : "help",
"href" : "https://icann.org/wicf",
"type" : "text/html"
"type" : "text/html",
"value": "https://example.tld/rdap/domains"
}
]
}

View File

@@ -13,7 +13,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -34,7 +35,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -69,12 +71,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domains"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -87,9 +91,10 @@
"links":
[
{
"rel": "alternate",
"rel": "glossary",
"href": "https://icann.org/epp",
"type": "text/html"
"type": "text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -99,9 +104,10 @@
"links":
[
{
"rel": "alternate",
"rel": "help",
"href": "https://icann.org/wicf",
"type": "text/html"
"type": "text/html",
"value": "https://example.tld/rdap/domains"
}
]
}

View File

@@ -28,12 +28,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "%REQUEST_URL%"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "%REQUEST_URL%"
}
],
"title": "RDAP Terms of Service"

View File

@@ -27,12 +27,14 @@
{
"rel" : "alternate",
"type" : "text/html",
"href" : "https://github.com/google/nomulus/blob/master/docs/rdap.md"
"href" : "https://github.com/google/nomulus/blob/master/docs/rdap.md",
"value": "https://example.tld/rdap/help%POSSIBLE_SLASH%"
},
{
"rel": "self",
"type": "application/rdap+json",
"href": "https://example.tld/rdap/help"
"href": "https://example.tld/rdap/help",
"value": "https://example.tld/rdap/help%POSSIBLE_SLASH%"
}
]
},
@@ -56,12 +58,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/help%POSSIBLE_SLASH%"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/help%POSSIBLE_SLASH%"
}
]
}

View File

@@ -26,12 +26,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/help/tos"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/help/tos"
}
]
}

View File

@@ -5,14 +5,15 @@
"icann_rdap_technical_implementation_guide_0"
],
"objectClassName": "nameserver",
"handle": "%HANDLE%",
"ldhName": "%NAME%",
"handle": "%NAMESERVER_HANDLE_1%",
"ldhName": "%NAMESERVER_NAME_1%",
"status": ["%STATUS%"],
"links": [
{
"href": "https://example.tld/rdap/nameserver/%NAME%",
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"ipAddresses": {
@@ -36,7 +37,8 @@
{
"rel" : "self",
"href" : "https://example.tld/rdap/entity/1",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "%REQUEST_URL%"
}
],
"publicIds" :

View File

@@ -7,15 +7,16 @@
"status": [
"active"
],
"handle": "%HANDLE%",
"handle": "%NAMESERVER_HANDLE_1%",
"links": [
{
"href": "https://example.tld/rdap/nameserver/%NAME%",
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"ldhName": "%NAME%",
"ldhName": "%NAMESERVER_NAME_1%",
"events": [
{
"eventAction": "last update of RDAP database",
@@ -33,7 +34,8 @@
{
"rel" : "self",
"href" : "https://example.tld/rdap/entity/1",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "%REQUEST_URL%"
}
],
"publicIds" :

View File

@@ -5,17 +5,18 @@
"icann_rdap_technical_implementation_guide_0"
],
"objectClassName": "nameserver",
"handle": "%HANDLE%",
"ldhName": "%NAME%",
"handle": "%NAMESERVER_HANDLE_1%",
"ldhName": "%NAMESERVER_NAME_1%",
"status": [
"active",
"associated"
],
"links": [
{
"href": "https://example.tld/rdap/nameserver/%NAME%",
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"ipAddresses": {
@@ -39,7 +40,8 @@
{
"rel" : "self",
"href" : "https://example.tld/rdap/entity/1",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "%REQUEST_URL%"
}
],
"publicIds" :

View File

@@ -5,15 +5,16 @@
"icann_rdap_technical_implementation_guide_0"
],
"objectClassName": "nameserver",
"handle": "%HANDLE%",
"ldhName": "%PUNYCODENAME%",
"unicodeName": "%NAME%",
"handle": "%NAMESERVER_HANDLE_1%",
"ldhName": "%NAMESERVER_NAME_1%",
"unicodeName": "%NAMESERVER_UNICODE_NAME_1%",
"status": ["active"],
"links": [
{
"href": "https://example.tld/rdap/nameserver/%PUNYCODENAME%",
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"ipAddresses": {
@@ -37,7 +38,8 @@
{
"rel" : "self",
"href" : "https://example.tld/rdap/entity/1",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "%REQUEST_URL%"
}
],
"publicIds" :

View File

@@ -9,7 +9,8 @@
{
"rel":"self",
"href":"https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type":"application/rdap+json"
"type":"application/rdap+json",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -31,7 +32,8 @@
{
"rel":"self",
"href":"https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_2%",
"type":"application/rdap+json"
"type":"application/rdap+json",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -53,7 +55,8 @@
{
"rel":"self",
"href":"https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_3%",
"type":"application/rdap+json"
"type":"application/rdap+json",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -97,12 +100,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domains"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/domains"
}
],
"title":"RDAP Terms of Service"
@@ -121,9 +126,10 @@
"links":
[
{
"rel":"alternate",
"rel":"glossary",
"href":"https://icann.org/epp",
"type":"text/html"
"type":"text/html",
"value": "https://example.tld/rdap/domains"
}
],
"title":"Status Codes"
@@ -134,9 +140,10 @@
"links":
[
{
"rel":"alternate",
"rel":"help",
"href":"https://icann.org/wicf",
"type":"text/html"
"type":"text/html",
"value": "https://example.tld/rdap/domains"
}
]
}

View File

@@ -17,7 +17,8 @@
{
"type":"application/rdap+json",
"rel":"self",
"href":"https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%"
"href":"https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -38,7 +39,8 @@
{
"type":"application/rdap+json",
"rel":"self",
"href":"https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_2%"
"href":"https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_2%",
"value": "https://example.tld/rdap/domains"
}
]
}
@@ -69,12 +71,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domains"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -91,8 +95,9 @@
"links":[
{
"type":"text/html",
"rel":"alternate",
"href":"https://icann.org/epp"
"rel":"glossary",
"href":"https://icann.org/epp",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -102,8 +107,9 @@
"links":[
{
"type":"text/html",
"rel":"alternate",
"href":"https://icann.org/wicf"
"rel":"help",
"href":"https://icann.org/wicf",
"value": "https://example.tld/rdap/domains"
}
]
}

View File

@@ -129,7 +129,7 @@
"type": "application/rdap+json"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
}

View File

@@ -9,7 +9,8 @@
{
"rel" : "self",
"href": "https://example.tld/rdap/entity/4-ROID",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"events": [
@@ -65,7 +66,8 @@
{
"rel" : "self",
"href": "https://example.tld/rdap/entity/2-ROID",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"events": [
@@ -141,12 +143,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/entities"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/entities"
}
]
},

View File

@@ -10,7 +10,8 @@
{
"rel" : "self",
"type" : "application/rdap+json",
"href" : "https://example.tld/rdap/nameserver/ns2.cat.lol"
"href" : "https://example.tld/rdap/nameserver/ns2.cat.lol",
"value": "https://example.tld/rdap/nameservers"
}
],
"ipAddresses" :
@@ -42,7 +43,8 @@
{
"rel" : "self",
"type" : "application/rdap+json",
"href" : "https://example.tld/rdap/nameserver/ns1.cat2.lol"
"href" : "https://example.tld/rdap/nameserver/ns1.cat2.lol",
"value": "https://example.tld/rdap/nameservers"
}
],
"ipAddresses" :
@@ -94,12 +96,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/nameservers"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/nameservers"
}
]
},

View File

@@ -9,7 +9,8 @@
{
"rel" : "self",
"href": "https://example.tld/rdap/entity/0001-ROID",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"events": [
@@ -65,7 +66,8 @@
{
"rel" : "self",
"href": "https://example.tld/rdap/entity/0002-ROID",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"events": [
@@ -121,7 +123,8 @@
{
"rel" : "self",
"href": "https://example.tld/rdap/entity/0003-ROID",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"events": [
@@ -177,7 +180,8 @@
{
"rel" : "self",
"href": "https://example.tld/rdap/entity/0004-ROID",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"events": [
@@ -253,12 +257,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/entities"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/entities"
}
]
},

View File

@@ -8,7 +8,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -29,7 +30,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -50,7 +52,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_3%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -71,7 +74,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_4%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -112,12 +116,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domains"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -136,9 +142,10 @@
"links" :
[
{
"rel" : "alternate",
"rel" : "glossary",
"href" : "https://icann.org/epp",
"type" : "text/html"
"type" : "text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -148,9 +155,10 @@
"links" :
[
{
"rel" : "alternate",
"rel" : "help",
"href" : "https://icann.org/wicf",
"type" : "text/html"
"type" : "text/html",
"value": "https://example.tld/rdap/domains"
}
]
}

View File

@@ -10,7 +10,8 @@
{
"rel" : "self",
"type" : "application/rdap+json",
"href" : "https://example.tld/rdap/nameserver/nsx1.cat.lol"
"href" : "https://example.tld/rdap/nameserver/nsx1.cat.lol",
"value": "https://example.tld/rdap/nameservers"
}
],
"ipAddresses" :
@@ -42,7 +43,8 @@
{
"rel" : "self",
"type" : "application/rdap+json",
"href" : "https://example.tld/rdap/nameserver/nsx2.cat.lol"
"href" : "https://example.tld/rdap/nameserver/nsx2.cat.lol",
"value": "https://example.tld/rdap/nameservers"
}
],
"ipAddresses" :
@@ -74,7 +76,8 @@
{
"rel" : "self",
"type" : "application/rdap+json",
"href" : "https://example.tld/rdap/nameserver/nsx3.cat.lol"
"href" : "https://example.tld/rdap/nameserver/nsx3.cat.lol",
"value": "https://example.tld/rdap/nameservers"
}
],
"ipAddresses" :
@@ -106,7 +109,8 @@
{
"rel" : "self",
"type" : "application/rdap+json",
"href" : "https://example.tld/rdap/nameserver/nsx4.cat.lol"
"href" : "https://example.tld/rdap/nameserver/nsx4.cat.lol",
"value": "https://example.tld/rdap/nameservers"
}
],
"ipAddresses" :
@@ -157,12 +161,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/nameservers"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/nameservers"
}
]
},

View File

@@ -9,7 +9,8 @@
{
"rel": "self",
"href": "https://example.tld/rdap/entity/301",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"publicIds":
@@ -66,7 +67,8 @@
{
"rel": "self",
"href": "https://example.tld/rdap/entity/302",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"publicIds":
@@ -123,7 +125,8 @@
{
"rel": "self",
"href": "https://example.tld/rdap/entity/303",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"publicIds":
@@ -180,7 +183,8 @@
{
"rel": "self",
"href": "https://example.tld/rdap/entity/304",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"publicIds":
@@ -257,12 +261,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/entities"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/entities"
}
]
},

View File

@@ -5,22 +5,23 @@
"icann_rdap_technical_implementation_guide_0"
],
"objectClassName" : "entity",
"handle" : "%NAME%",
"status" : ["%STATUS%"],
"handle" : "%REGISTRAR_HANDLE_1%",
"status" : ["%STATUS_1%"],
"roles" : ["registrar"],
"links" :
[
{
"rel" : "self",
"href": "https://example.tld/rdap/entity/%NAME%",
"type" : "application/rdap+json"
"href": "https://example.tld/rdap/entity/%REGISTRAR_HANDLE_1%",
"type" : "application/rdap+json",
"value": "%REQUEST_URL%"
}
],
"publicIds" :
[
{
"type" : "IANA Registrar ID",
"identifier" : "%NAME%"
"identifier" : "%REGISTRAR_HANDLE_1%"
}
],
"events": [
@@ -34,7 +35,7 @@
"vcard",
[
["version", {}, "text", "4.0"],
["fn", {}, "text", "%FULLNAME%"],
["fn", {}, "text", "%REGISTRAR_FULLNAME_1%"],
["adr", {}, "text",
[
"",

View File

@@ -5,8 +5,8 @@
"icann_rdap_technical_implementation_guide_0"
],
"objectClassName" : "entity",
"handle" : "%NAME%",
"status" : ["%STATUS%"],
"handle" : "%REGISTRAR_HANDLE_1%",
"status" : ["%STATUS_1%"],
"roles" : ["registrar"],
"events": [
{
@@ -19,7 +19,7 @@
"vcard",
[
["version", {}, "text", "4.0"],
["fn", {}, "text", "%FULLNAME%"],
["fn", {}, "text", "%REGISTRAR_FULLNAME_1%"],
["adr", {}, "text",
[
"",

View File

@@ -9,7 +9,8 @@
{
"rel": "self",
"href": "https://example.tld/rdap/entity/0001-ROID",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"events": [
@@ -65,7 +66,8 @@
{
"rel": "self",
"href": "https://example.tld/rdap/entity/0002-ROID",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"events": [
@@ -121,7 +123,8 @@
{
"rel": "self",
"href": "https://example.tld/rdap/entity/0003-ROID",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"events": [
@@ -177,7 +180,8 @@
{
"rel": "self",
"href": "https://example.tld/rdap/entity/0004-ROID",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"events": [
@@ -248,7 +252,8 @@
{
"type": "application/rdap+json",
"href": "https://example.tld/rdap/entities?%NAME%",
"rel": "next"
"rel": "next",
"value": "https://example.tld/rdap/entities"
}
],
"description": [ "Links to related pages." ]
@@ -273,12 +278,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/entities"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/entities"
}
]
},

View File

@@ -10,7 +10,8 @@
{
"rel" : "self",
"type" : "application/rdap+json",
"href" : "https://example.tld/rdap/nameserver/nsx1.cat.lol"
"href" : "https://example.tld/rdap/nameserver/nsx1.cat.lol",
"value": "https://example.tld/rdap/nameservers"
}
],
"ipAddresses" :
@@ -42,7 +43,8 @@
{
"rel" : "self",
"type" : "application/rdap+json",
"href" : "https://example.tld/rdap/nameserver/nsx2.cat.lol"
"href" : "https://example.tld/rdap/nameserver/nsx2.cat.lol",
"value": "https://example.tld/rdap/nameservers"
}
],
"ipAddresses" :
@@ -74,7 +76,8 @@
{
"rel" : "self",
"type" : "application/rdap+json",
"href" : "https://example.tld/rdap/nameserver/nsx3.cat.lol"
"href" : "https://example.tld/rdap/nameserver/nsx3.cat.lol",
"value": "https://example.tld/rdap/nameservers"
}
],
"ipAddresses" :
@@ -106,7 +109,8 @@
{
"rel" : "self",
"type" : "application/rdap+json",
"href" : "https://example.tld/rdap/nameserver/nsx4.cat.lol"
"href" : "https://example.tld/rdap/nameserver/nsx4.cat.lol",
"value": "https://example.tld/rdap/nameservers"
}
],
"ipAddresses" :
@@ -153,7 +157,8 @@
{
"type" : "application/rdap+json",
"rel" : "next",
"href" : "https://example.tld/rdap/nameservers?%QUERY%"
"href" : "https://example.tld/rdap/nameservers?%QUERY%",
"value": "https://example.tld/rdap/nameservers"
}
]
},
@@ -177,12 +182,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/nameservers"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/nameservers"
}
]
},

View File

@@ -9,7 +9,8 @@
{
"rel" : "self",
"href": "https://example.tld/rdap/entity/0001-ROID",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"events": [
@@ -65,7 +66,8 @@
{
"rel" : "self",
"href": "https://example.tld/rdap/entity/0002-ROID",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"events": [
@@ -121,7 +123,8 @@
{
"rel" : "self",
"href": "https://example.tld/rdap/entity/0003-ROID",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"events": [
@@ -177,7 +180,8 @@
{
"rel" : "self",
"href": "https://example.tld/rdap/entity/301",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"publicIds" :
@@ -249,7 +253,8 @@
{
"type" : "application/rdap+json",
"href" : "https://example.tld/rdap/entities?%NAME%",
"rel" : "next"
"rel" : "next",
"value": "https://example.tld/rdap/entities"
}
],
"description" : [ "Links to related pages." ]
@@ -274,12 +279,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/entities"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/entities"
}
]
},

View File

@@ -9,7 +9,8 @@
{
"rel" : "self",
"href": "https://example.tld/rdap/entity/301",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"publicIds" :
@@ -66,7 +67,8 @@
{
"rel" : "self",
"href": "https://example.tld/rdap/entity/302",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"publicIds" :
@@ -123,7 +125,8 @@
{
"rel" : "self",
"href": "https://example.tld/rdap/entity/303",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"publicIds" :
@@ -180,7 +183,8 @@
{
"rel" : "self",
"href": "https://example.tld/rdap/entity/304",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "https://example.tld/rdap/entities"
}
],
"publicIds" :
@@ -252,7 +256,8 @@
{
"type" : "application/rdap+json",
"href" : "https://example.tld/rdap/entities?%NAME%",
"rel" : "next"
"rel" : "next",
"value": "https://example.tld/rdap/entities"
}
],
"description" : [ "Links to related pages." ]
@@ -277,12 +282,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/entities"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/entities"
}
]
},

View File

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

View File

@@ -30,8 +30,8 @@
"type": "application/rdap+json"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html"
}
]

Some files were not shown because too many files have changed in this diff Show More