mirror of
https://github.com/google/nomulus
synced 2026-05-26 09:41:09 +00:00
Compare commits
6 Commits
proxy-2023
...
proxy-2023
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d22c2a8d8 | ||
|
|
fe19f0fe78 | ||
|
|
599a55d5b1 | ||
|
|
845f792044 | ||
|
|
ad68052524 | ||
|
|
04c6652793 |
@@ -505,6 +505,7 @@ task javaIncrementalFormatCheck {
|
||||
println("Omitting format check: not in a git directory.")
|
||||
}
|
||||
}
|
||||
dependsOn('console-webapp:checkFormatting')
|
||||
}
|
||||
|
||||
// Shows how modified lines in Java source files will change after formatting.
|
||||
@@ -522,6 +523,7 @@ task javaIncrementalFormatApply {
|
||||
doLast {
|
||||
invokeJavaDiffFormatScript("format")
|
||||
}
|
||||
dependsOn('console-webapp:applyFormatting')
|
||||
}
|
||||
|
||||
task javadoc(type: Javadoc) {
|
||||
|
||||
@@ -50,12 +50,19 @@ task buildConsoleWebappProd(type: Exec) {
|
||||
args 'run', 'build'
|
||||
}
|
||||
|
||||
task applyFormatting() {
|
||||
exec {
|
||||
workingDir "${consoleDir}/"
|
||||
commandLine 'npm', 'run', 'prettify'
|
||||
}
|
||||
task applyFormatting(type: Exec) {
|
||||
workingDir "${consoleDir}/"
|
||||
executable 'npm'
|
||||
args 'run', 'prettify'
|
||||
}
|
||||
|
||||
task checkFormatting(type: Exec) {
|
||||
workingDir "${consoleDir}/"
|
||||
executable 'npm'
|
||||
args 'run', 'prettify:check'
|
||||
}
|
||||
|
||||
tasks.runConsoleWebappUnitTests.dependsOn(tasks.npmInstallDeps)
|
||||
tasks.buildConsoleWebappProd.dependsOn(tasks.npmInstallDeps)
|
||||
tasks.applyFormatting.dependsOn(tasks.npmInstallDeps)
|
||||
tasks.checkFormatting.dependsOn(tasks.npmInstallDeps)
|
||||
|
||||
1729
console-webapp/package-lock.json
generated
1729
console-webapp/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,7 @@
|
||||
"test": "ng test --browsers=ChromeHeadless --watch=false",
|
||||
"run:dev": "",
|
||||
"prettify": "npx prettier --write ./src/",
|
||||
"prettify:check": "npx prettier --check ./src/",
|
||||
"start:dev": "concurrently \"./../gradlew :core:runTestServer\" \"ng serve --proxy-config dev-proxy.config.json\"",
|
||||
"lint": "ng lint"
|
||||
},
|
||||
|
||||
@@ -144,15 +144,13 @@ public class CloudDnsWriter extends BaseDnsWriter {
|
||||
dsRrData.add(ds.toRrData());
|
||||
}
|
||||
|
||||
if (!dsRrData.isEmpty()) {
|
||||
domainRecords.add(
|
||||
new ResourceRecordSet()
|
||||
.setName(absoluteDomainName)
|
||||
.setTtl((int) tld.getDnsDsTtl().orElse(defaultDsTtl).getStandardSeconds())
|
||||
.setType("DS")
|
||||
.setKind("dns#resourceRecordSet")
|
||||
.setRrdatas(ImmutableList.copyOf(dsRrData)));
|
||||
}
|
||||
domainRecords.add(
|
||||
new ResourceRecordSet()
|
||||
.setName(absoluteDomainName)
|
||||
.setTtl((int) tld.getDnsDsTtl().orElse(defaultDsTtl).getStandardSeconds())
|
||||
.setType("DS")
|
||||
.setKind("dns#resourceRecordSet")
|
||||
.setRrdatas(ImmutableList.copyOf(dsRrData)));
|
||||
}
|
||||
|
||||
// Construct NS records (if any).
|
||||
@@ -169,15 +167,13 @@ public class CloudDnsWriter extends BaseDnsWriter {
|
||||
}
|
||||
}
|
||||
|
||||
if (!nsRrData.isEmpty()) {
|
||||
domainRecords.add(
|
||||
new ResourceRecordSet()
|
||||
.setName(absoluteDomainName)
|
||||
.setTtl((int) tld.getDnsNsTtl().orElse(defaultNsTtl).getStandardSeconds())
|
||||
.setType("NS")
|
||||
.setKind("dns#resourceRecordSet")
|
||||
.setRrdatas(ImmutableList.copyOf(nsRrData)));
|
||||
}
|
||||
domainRecords.add(
|
||||
new ResourceRecordSet()
|
||||
.setName(absoluteDomainName)
|
||||
.setTtl((int) tld.getDnsNsTtl().orElse(defaultNsTtl).getStandardSeconds())
|
||||
.setType("NS")
|
||||
.setKind("dns#resourceRecordSet")
|
||||
.setRrdatas(ImmutableList.copyOf(nsRrData)));
|
||||
}
|
||||
|
||||
desiredRecords.put(absoluteDomainName, domainRecords.build());
|
||||
|
||||
@@ -367,7 +367,7 @@ final class RdapDataStructures {
|
||||
PENDING_RESTORE("pending restore"),
|
||||
REDEMPTION_PERIOD("redemption period"),
|
||||
RENEW_PERIOD("renew period"),
|
||||
SERVER_DELETE_PROHIBITED("server deleted prohibited"),
|
||||
SERVER_DELETE_PROHIBITED("server delete prohibited"),
|
||||
SERVER_RENEW_PROHIBITED("server renew prohibited"),
|
||||
SERVER_TRANSFER_PROHIBITED("server transfer prohibited"),
|
||||
SERVER_UPDATE_PROHIBITED("server update prohibited"),
|
||||
|
||||
@@ -54,12 +54,11 @@ public class RdapIcannStandardInformation {
|
||||
private static final Notice INACCURACY_COMPLAINT_FORM_NOTICE =
|
||||
Notice.builder()
|
||||
.setTitle("RDDS Inaccuracy Complaint Form")
|
||||
.setDescription(
|
||||
"URL of the ICANN RDDS Inaccuracy Complaint Form: https://www.icann.org/wicf")
|
||||
.setDescription("URL of the ICANN RDDS Inaccuracy Complaint Form: https://icann.org/wicf")
|
||||
.addLink(
|
||||
Link.builder()
|
||||
.setRel("alternate")
|
||||
.setHref("https://www.icann.org/wicf")
|
||||
.setHref("https://icann.org/wicf")
|
||||
.setType("text/html")
|
||||
.build())
|
||||
.build();
|
||||
@@ -150,14 +149,6 @@ public class RdapIcannStandardInformation {
|
||||
.build())
|
||||
.build();
|
||||
|
||||
/**
|
||||
* String that replaces GDPR redacted values.
|
||||
*
|
||||
* <p>GTLD Registration Data Temp Spec 17may18, Appendix A, 2.2: Fields required to be "redacted"
|
||||
* MUST privide in the value section text similar to "REDACTED FOR PRIVACY"
|
||||
*/
|
||||
static final String CONTACT_REDACTED_VALUE = "REDACTED FOR PRIVACY";
|
||||
|
||||
/**
|
||||
* Included in ALL contact responses, even if the user is authorized.
|
||||
*
|
||||
|
||||
@@ -21,7 +21,6 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.collect.ImmutableSetMultimap.toImmutableSetMultimap;
|
||||
import static google.registry.model.EppResourceUtils.isLinked;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.replicaTm;
|
||||
import static google.registry.rdap.RdapIcannStandardInformation.CONTACT_REDACTED_VALUE;
|
||||
import static google.registry.util.CollectionUtils.union;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
@@ -39,7 +38,6 @@ import com.google.gson.JsonArray;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.model.EppResource;
|
||||
import google.registry.model.contact.Contact;
|
||||
import google.registry.model.contact.ContactAddress;
|
||||
import google.registry.model.contact.ContactPhoneNumber;
|
||||
import google.registry.model.contact.PostalInfo;
|
||||
import google.registry.model.domain.DesignatedContact;
|
||||
@@ -519,69 +517,68 @@ public class RdapJsonFormatter {
|
||||
boolean isAuthorized =
|
||||
rdapAuthorization.isAuthorizedForRegistrar(contact.getCurrentSponsorRegistrarId());
|
||||
|
||||
// ROID needs to be redacted if we aren't authorized, so we can't have a self-link for
|
||||
// unauthorized users
|
||||
VcardArray.Builder vcardBuilder = VcardArray.builder();
|
||||
|
||||
if (isAuthorized) {
|
||||
contactBuilder.linksBuilder().add(makeSelfLink("entity", contact.getRepoId()));
|
||||
}
|
||||
|
||||
// Only show the "summary data remark" if the user is authorized to see this data - because
|
||||
// unauthorized users don't have a self link meaning they can't navigate to the full data.
|
||||
if (outputDataType != OutputDataType.FULL && isAuthorized) {
|
||||
contactBuilder.remarksBuilder().add(RdapIcannStandardInformation.SUMMARY_DATA_REMARK);
|
||||
}
|
||||
|
||||
// GTLD Registration Data Temp Spec 17may18, Appendix A, 2.3, 2.4 and RDAP Response Profile
|
||||
// 2.7.4.1, 2.7.4.2 - the following fields must be redacted:
|
||||
// for REGISTRANT:
|
||||
// handle (ROID), FN (name), TEL (telephone/fax and extension), street, city, postal code
|
||||
// for ADMIN, TECH:
|
||||
// handle (ROID), FN (name), TEL (telephone/fax and extension), Organization, street, city,
|
||||
// state/province, postal code, country
|
||||
//
|
||||
// Note that in theory we have to show the Organization and state/province and country for the
|
||||
// REGISTRANT. For now, we won't do that until we make sure it's really OK for GDPR
|
||||
//
|
||||
if (!isAuthorized) {
|
||||
fillRdapContactEntityWhenAuthorized(contactBuilder, vcardBuilder, contact, outputDataType);
|
||||
} else {
|
||||
// GTLD Registration Data Temp Spec 17may18, Appendix A, 2.3, 2.4 and RDAP Response Profile
|
||||
// 2.7.4.1, 2.7.4.2 - the following fields must be redacted:
|
||||
// for REGISTRANT:
|
||||
// handle (ROID), FN (name), TEL (telephone/fax and extension), street, city, postal code
|
||||
// for ADMIN, TECH:
|
||||
// handle (ROID), FN (name), TEL (telephone/fax and extension), Organization, street, city,
|
||||
// state/province, postal code, country
|
||||
//
|
||||
// Note that in theory we have to show the Organization and state/province and country for the
|
||||
// REGISTRANT. For now, we won't do that until we make sure it's really OK for GDPR
|
||||
//
|
||||
// RDAP Response Profile 2.7.4.3: if we redact values from the contact, we MUST include a
|
||||
// remark
|
||||
contactBuilder
|
||||
.remarksBuilder()
|
||||
.add(RdapIcannStandardInformation.CONTACT_PERSONAL_DATA_HIDDEN_DATA_REMARK);
|
||||
// to make sure we don't accidentally display data we shouldn't - we replace the
|
||||
// contact with a safe resource. Then we can add any information we need (e.g. the
|
||||
// Organization / state / country of the registrant), although we currently don't do that.
|
||||
contact =
|
||||
new Contact.Builder()
|
||||
.setRepoId(CONTACT_REDACTED_VALUE)
|
||||
.setVoiceNumber(
|
||||
new ContactPhoneNumber.Builder().setPhoneNumber(CONTACT_REDACTED_VALUE).build())
|
||||
.setFaxNumber(
|
||||
new ContactPhoneNumber.Builder().setPhoneNumber(CONTACT_REDACTED_VALUE).build())
|
||||
.setInternationalizedPostalInfo(
|
||||
new PostalInfo.Builder()
|
||||
.setName(CONTACT_REDACTED_VALUE)
|
||||
.setOrg(CONTACT_REDACTED_VALUE)
|
||||
.setType(PostalInfo.Type.INTERNATIONALIZED)
|
||||
.setAddress(
|
||||
new ContactAddress.Builder()
|
||||
.setStreet(ImmutableList.of(CONTACT_REDACTED_VALUE))
|
||||
.setCity(CONTACT_REDACTED_VALUE)
|
||||
.setState(CONTACT_REDACTED_VALUE)
|
||||
.setZip(CONTACT_REDACTED_VALUE)
|
||||
.setCountryCode("XX")
|
||||
.build())
|
||||
.build())
|
||||
.build();
|
||||
contactBuilder.setHandle("");
|
||||
// The VCard format requires a "fn" entry even if it is empty (redacted)
|
||||
vcardBuilder.add(Vcard.create("fn", "text", ""));
|
||||
}
|
||||
|
||||
// RDAP Response Profile 2.7.3 - we MUST provide a handle set with the ROID, subject to the
|
||||
// redaction above.
|
||||
contactBuilder.setHandle(contact.getRepoId());
|
||||
contactBuilder.setVcardArray(vcardBuilder.build());
|
||||
contactBuilder.rolesBuilder().addAll(roles);
|
||||
|
||||
// RDAP Response Profile doesn't mention status for contacts, so we only show it if we're both
|
||||
// FULL and Authorized.
|
||||
if (outputDataType == OutputDataType.FULL && isAuthorized) {
|
||||
// RDAP Response Profile 2.7.5.1, 2.7.5.3:
|
||||
// email MUST be omitted, and we MUST have a Remark saying so
|
||||
contactBuilder
|
||||
.remarksBuilder()
|
||||
.add(RdapIcannStandardInformation.CONTACT_EMAIL_REDACTED_FOR_DOMAIN);
|
||||
|
||||
if (outputDataType != OutputDataType.INTERNAL) {
|
||||
// Rdap Response Profile 2.7.6 must have "last update of RDAP database" response. But this is
|
||||
// only for direct query responses and not for internal objects. I'm not sure why it's in that
|
||||
// section at all...
|
||||
contactBuilder.setLastUpdateOfRdapDatabaseEvent(
|
||||
Event.builder()
|
||||
.setEventAction(EventAction.LAST_UPDATE_OF_RDAP_DATABASE)
|
||||
.setEventDate(getRequestTime())
|
||||
.build());
|
||||
}
|
||||
return contactBuilder.build();
|
||||
}
|
||||
|
||||
private void fillRdapContactEntityWhenAuthorized(
|
||||
RdapContactEntity.Builder contactBuilder,
|
||||
VcardArray.Builder vcardBuilder,
|
||||
Contact contact,
|
||||
OutputDataType outputDataType) {
|
||||
// ROID needs to be redacted if we aren't authorized, so we can't have a self-link for
|
||||
// unauthorized users
|
||||
contactBuilder.linksBuilder().add(makeSelfLink("entity", contact.getRepoId()));
|
||||
// RDAP Response Profile 2.7.3 - we MUST provide a handle set with the ROID, subject to
|
||||
// redaction.
|
||||
contactBuilder.setHandle(contact.getRepoId());
|
||||
if (outputDataType.equals(OutputDataType.FULL)) {
|
||||
// RDAP Response Profile doesn't mention status for contacts, so we only show it if we're both
|
||||
// FULL and Authorized.
|
||||
contactBuilder
|
||||
.statusBuilder()
|
||||
.addAll(
|
||||
@@ -591,12 +588,18 @@ public class RdapJsonFormatter {
|
||||
: contact.getStatusValues(),
|
||||
false,
|
||||
contact.getDeletionTime().isBefore(getRequestTime())));
|
||||
// If we are outputting all data (not just summary data), also add events taken from the
|
||||
// history entries. This isn't strictly required.
|
||||
//
|
||||
// We also only add it for authorized users because millisecond times can fingerprint a user
|
||||
// just as much as the handle can.
|
||||
contactBuilder.eventsBuilder().addAll(makeOptionalEvents(contact));
|
||||
} else {
|
||||
// Only show the "summary data remark" if the user is authorized to see this data - because
|
||||
// unauthorized users don't have a self link meaning they can't navigate to the full data.
|
||||
contactBuilder.remarksBuilder().add(RdapIcannStandardInformation.SUMMARY_DATA_REMARK);
|
||||
}
|
||||
|
||||
contactBuilder.rolesBuilder().addAll(roles);
|
||||
|
||||
VcardArray.Builder vcardBuilder = VcardArray.builder();
|
||||
// Adding the VCard members subject to the redaction above.
|
||||
// Adding the VCard members when not redacted.
|
||||
//
|
||||
// RDAP Response Profile 2.7.3 - we MUST have FN, ADR, TEL, EMAIL.
|
||||
//
|
||||
@@ -622,33 +625,6 @@ public class RdapJsonFormatter {
|
||||
if (faxPhoneNumber != null) {
|
||||
vcardBuilder.add(makePhoneEntry(PHONE_TYPE_FAX, makePhoneString(faxPhoneNumber)));
|
||||
}
|
||||
// RDAP Response Profile 2.7.5.1, 2.7.5.3:
|
||||
// email MUST be omitted, and we MUST have a Remark saying so
|
||||
contactBuilder
|
||||
.remarksBuilder()
|
||||
.add(RdapIcannStandardInformation.CONTACT_EMAIL_REDACTED_FOR_DOMAIN);
|
||||
contactBuilder.setVcardArray(vcardBuilder.build());
|
||||
|
||||
if (outputDataType != OutputDataType.INTERNAL) {
|
||||
// Rdap Response Profile 2.7.6 must have "last update of RDAP database" response. But this is
|
||||
// only for direct query responses and not for internal objects. I'm not sure why it's in that
|
||||
// section at all...
|
||||
contactBuilder.setLastUpdateOfRdapDatabaseEvent(
|
||||
Event.builder()
|
||||
.setEventAction(EventAction.LAST_UPDATE_OF_RDAP_DATABASE)
|
||||
.setEventDate(getRequestTime())
|
||||
.build());
|
||||
}
|
||||
|
||||
// If we are outputting all data (not just summary data), also add events taken from the history
|
||||
// entries. This isn't strictly required.
|
||||
//
|
||||
// We also only add it for authorized users because millisecond times can fingerprint a user
|
||||
// just as much as the handle can.
|
||||
if (outputDataType == OutputDataType.FULL && isAuthorized) {
|
||||
contactBuilder.eventsBuilder().addAll(makeOptionalEvents(contact));
|
||||
}
|
||||
return contactBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1000,7 +976,7 @@ public class RdapJsonFormatter {
|
||||
// Gustavo Lozano of ICANN, the one we should use is an embedded array of street address lines
|
||||
// if there is more than one line:
|
||||
//
|
||||
// RFC7095 provides two examples of structured addresses, and one of the examples shows a
|
||||
// RFC 7095 provides two examples of structured addresses, and one of the examples shows a
|
||||
// street JSON element that contains several data elements. The example showing (see below)
|
||||
// several data elements is the expected output when two or more <contact:street> elements
|
||||
// exists in the contact object.
|
||||
|
||||
@@ -24,7 +24,6 @@ import google.registry.model.tld.label.PremiumList;
|
||||
import google.registry.model.tld.label.PremiumListDao;
|
||||
import google.registry.model.tld.label.PremiumListUtils;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Optional;
|
||||
|
||||
/** Command to safely update {@link PremiumList} in Database for a given TLD. */
|
||||
@Parameters(separators = " =", commandDescription = "Update a PremiumList in Database.")
|
||||
@@ -33,16 +32,19 @@ class UpdatePremiumListCommand extends CreateOrUpdatePremiumListCommand {
|
||||
@Override
|
||||
protected String prompt() throws Exception {
|
||||
name = Strings.isNullOrEmpty(name) ? convertFilePathToName(inputFile) : name;
|
||||
Optional<PremiumList> list = PremiumListDao.getLatestRevision(name);
|
||||
checkArgument(
|
||||
list.isPresent(),
|
||||
String.format("Could not update premium list %s because it doesn't exist.", name));
|
||||
PremiumList existingList =
|
||||
PremiumListDao.getLatestRevision(name)
|
||||
.orElseThrow(
|
||||
() ->
|
||||
new IllegalArgumentException(
|
||||
String.format(
|
||||
"Could not update premium list %s because it doesn't exist", name)));
|
||||
inputData = Files.readAllLines(inputFile, UTF_8);
|
||||
checkArgument(!inputData.isEmpty(), "New premium list data cannot be empty");
|
||||
currency = list.get().getCurrency();
|
||||
currency = existingList.getCurrency();
|
||||
PremiumList updatedPremiumList = PremiumListUtils.parseToPremiumList(name, currency, inputData);
|
||||
return String.format(
|
||||
"Update premium list for %s?\n Old List: %s\n New List: %s",
|
||||
name, list, updatedPremiumList);
|
||||
name, existingList, updatedPremiumList);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,9 @@ import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.persistence.TypedQuery;
|
||||
import org.apache.arrow.util.VisibleForTesting;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.joda.time.Duration;
|
||||
@@ -85,11 +87,14 @@ public class RefreshDnsForAllDomainsAction implements Runnable {
|
||||
assertTldsExist(tlds);
|
||||
checkArgument(batchSize > 0, "Must specify a positive number for batch size");
|
||||
int smearMinutes = tm().transact(this::calculateSmearMinutes);
|
||||
ImmutableList<String> previousBatch = ImmutableList.of("");
|
||||
|
||||
ImmutableList<String> domainsBatch;
|
||||
@Nullable String lastInPreviousBatch = null;
|
||||
do {
|
||||
String lastInPreviousBatch = getLast(previousBatch);
|
||||
previousBatch = tm().transact(() -> refreshBatch(lastInPreviousBatch, smearMinutes));
|
||||
} while (previousBatch.size() == batchSize);
|
||||
Optional<String> lastInPreviousBatchOpt = Optional.ofNullable(lastInPreviousBatch);
|
||||
domainsBatch = tm().transact(() -> refreshBatch(lastInPreviousBatchOpt, smearMinutes));
|
||||
lastInPreviousBatch = domainsBatch.isEmpty() ? null : getLast(domainsBatch);
|
||||
} while (domainsBatch.size() == batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,22 +112,22 @@ public class RefreshDnsForAllDomainsAction implements Runnable {
|
||||
return Math.max(activeDomains.intValue() / 1000, 1);
|
||||
}
|
||||
|
||||
private ImmutableList<String> getBatch(String lastInPreviousBatch) {
|
||||
return tm().query(
|
||||
private ImmutableList<String> getBatch(Optional<String> lastInPreviousBatch) {
|
||||
String sql =
|
||||
String.format(
|
||||
"SELECT domainName FROM Domain WHERE tld IN (:tlds) AND"
|
||||
+ " deletionTime = :endOfTime AND domainName >"
|
||||
+ " :lastInPreviousBatch ORDER BY domainName ASC",
|
||||
String.class)
|
||||
.setParameter("tlds", tlds)
|
||||
.setParameter("endOfTime", END_OF_TIME)
|
||||
.setParameter("lastInPreviousBatch", lastInPreviousBatch)
|
||||
.setMaxResults(batchSize)
|
||||
.getResultStream()
|
||||
.collect(toImmutableList());
|
||||
+ " deletionTime = :endOfTime %s ORDER BY domainName ASC",
|
||||
lastInPreviousBatch.isPresent() ? "AND domainName > :lastInPreviousBatch" : "");
|
||||
TypedQuery<String> query =
|
||||
tm().query(sql, String.class)
|
||||
.setParameter("tlds", tlds)
|
||||
.setParameter("endOfTime", END_OF_TIME);
|
||||
lastInPreviousBatch.ifPresent(l -> query.setParameter("lastInPreviousBatch", l));
|
||||
return query.setMaxResults(batchSize).getResultStream().collect(toImmutableList());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
ImmutableList<String> refreshBatch(String lastInPreviousBatch, int smearMinutes) {
|
||||
ImmutableList<String> refreshBatch(Optional<String> lastInPreviousBatch, int smearMinutes) {
|
||||
ImmutableList<String> domainBatch = getBatch(lastInPreviousBatch);
|
||||
try {
|
||||
// Smear the task execution time over the next N minutes.
|
||||
|
||||
@@ -139,13 +139,12 @@ class RdapTestHelper {
|
||||
"RDDS Inaccuracy Complaint Form",
|
||||
"description",
|
||||
ImmutableList.of(
|
||||
"URL of the ICANN RDDS Inaccuracy Complaint Form:"
|
||||
+ " https://www.icann.org/wicf"),
|
||||
"URL of the ICANN RDDS Inaccuracy Complaint Form: https://icann.org/wicf"),
|
||||
"links",
|
||||
ImmutableList.of(
|
||||
ImmutableMap.of(
|
||||
"rel", "alternate",
|
||||
"href", "https://www.icann.org/wicf",
|
||||
"href", "https://icann.org/wicf",
|
||||
"type", "text/html")))));
|
||||
}
|
||||
|
||||
|
||||
@@ -134,15 +134,13 @@ class UpdatePremiumListCommandTest<C extends UpdatePremiumListCommand>
|
||||
|
||||
@Test
|
||||
void commandPrompt_failureNoPreviousVersion() {
|
||||
String fileName = "random";
|
||||
registry = createTld(fileName, null, null);
|
||||
registry = createTld("random", null, null);
|
||||
UpdatePremiumListCommand command = new UpdatePremiumListCommand();
|
||||
command.name = fileName;
|
||||
command.name = "random";
|
||||
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, command::prompt);
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.isEqualTo(
|
||||
String.format("Could not update premium list %s because it doesn't exist.", fileName));
|
||||
.isEqualTo("Could not update premium list random because it doesn't exist");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -153,27 +151,22 @@ class UpdatePremiumListCommandTest<C extends UpdatePremiumListCommand>
|
||||
|
||||
@Test
|
||||
void commandPrompt_failureTldFromNameDoesNotExist() {
|
||||
String fileName = "random";
|
||||
UpdatePremiumListCommand command = new UpdatePremiumListCommand();
|
||||
command.name = fileName;
|
||||
command.name = "random2";
|
||||
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, command::prompt);
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.isEqualTo(
|
||||
String.format("Could not update premium list %s because it doesn't exist.", fileName));
|
||||
.isEqualTo("Could not update premium list random2 because it doesn't exist");
|
||||
}
|
||||
|
||||
@Test
|
||||
void commandPrompt_failureTldFromInputFileDoesNotExist() {
|
||||
String fileName = "random";
|
||||
UpdatePremiumListCommand command = new UpdatePremiumListCommand();
|
||||
// using tld extracted from file name but this tld is not part of the registry
|
||||
command.inputFile =
|
||||
Paths.get(tmpDir.resolve(String.format("%s.txt", fileName)).toFile().getPath());
|
||||
command.inputFile = Paths.get(tmpDir.resolve("random3.txt").toFile().getPath());
|
||||
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, command::prompt);
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.isEqualTo(
|
||||
String.format("Could not update premium list %s because it doesn't exist.", fileName));
|
||||
.isEqualTo("Could not update premium list random3 because it doesn't exist");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,8 +75,8 @@ public class RefreshDnsForAllDomainsActionTest {
|
||||
action =
|
||||
new RefreshDnsForAllDomainsAction(
|
||||
response, ImmutableSet.of("bar"), Optional.of(1), new Random());
|
||||
tm().transact(() -> action.refreshBatch("", 1000));
|
||||
tm().transact(() -> action.refreshBatch("", 1000));
|
||||
tm().transact(() -> action.refreshBatch(Optional.empty(), 1000));
|
||||
tm().transact(() -> action.refreshBatch(Optional.empty(), 1000));
|
||||
ImmutableList<DnsRefreshRequest> refreshRequests =
|
||||
tm().transact(
|
||||
() ->
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"icann_rdap_technical_implementation_guide_0"
|
||||
],
|
||||
"objectClassName" : "entity",
|
||||
"handle" : "REDACTED FOR PRIVACY",
|
||||
"handle" : "",
|
||||
"events": [
|
||||
{
|
||||
"eventAction": "last update of RDAP database",
|
||||
@@ -15,25 +15,8 @@
|
||||
"vcardArray": [
|
||||
"vcard",
|
||||
[
|
||||
["version",{},"text","4.0"],
|
||||
["fn",{},"text","REDACTED FOR PRIVACY"],
|
||||
["org",{},"text","REDACTED FOR PRIVACY"],
|
||||
[
|
||||
"adr",
|
||||
{},
|
||||
"text",
|
||||
[
|
||||
"",
|
||||
"",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"XX"
|
||||
]
|
||||
],
|
||||
["tel",{"type":["voice"]},"uri","tel:REDACTED FOR PRIVACY"],
|
||||
["tel",{"type":["fax"]},"uri","tel:REDACTED FOR PRIVACY"]
|
||||
["version", {}, "text", "4.0"],
|
||||
["fn", {}, "text", ""]
|
||||
]
|
||||
],
|
||||
"remarks": [
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"icann_rdap_technical_implementation_guide_0"
|
||||
],
|
||||
"objectClassName" : "entity",
|
||||
"handle" : "REDACTED FOR PRIVACY",
|
||||
"handle" : "",
|
||||
"events": [
|
||||
{
|
||||
"eventAction": "last update of RDAP database",
|
||||
@@ -15,25 +15,8 @@
|
||||
"vcardArray": [
|
||||
"vcard",
|
||||
[
|
||||
["version",{},"text","4.0"],
|
||||
["fn",{},"text","REDACTED FOR PRIVACY"],
|
||||
["org",{},"text","REDACTED FOR PRIVACY"],
|
||||
[
|
||||
"adr",
|
||||
{},
|
||||
"text",
|
||||
[
|
||||
"",
|
||||
"",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"XX"
|
||||
]
|
||||
],
|
||||
["tel",{"type":["voice"]},"uri","tel:REDACTED FOR PRIVACY"],
|
||||
["tel",{"type":["fax"]},"uri","tel:REDACTED FOR PRIVACY"]
|
||||
["version", {}, "text", "4.0"],
|
||||
["fn", {}, "text", ""]
|
||||
]
|
||||
],
|
||||
"remarks": [
|
||||
|
||||
@@ -150,7 +150,7 @@
|
||||
},
|
||||
{
|
||||
"objectClassName": "entity",
|
||||
"handle": "REDACTED FOR PRIVACY",
|
||||
"handle": "",
|
||||
"roles":["administrative"],
|
||||
"remarks": [
|
||||
{
|
||||
@@ -180,18 +180,14 @@
|
||||
"vcard",
|
||||
[
|
||||
["version", {}, "text", "4.0"],
|
||||
["fn", {}, "text", "REDACTED FOR PRIVACY"],
|
||||
["org", {}, "text", "REDACTED FOR PRIVACY"],
|
||||
["adr", {}, "text", ["", "", "REDACTED FOR PRIVACY", "REDACTED FOR PRIVACY", "REDACTED FOR PRIVACY", "REDACTED FOR PRIVACY", "XX"]],
|
||||
["tel", {"type":["voice"]}, "uri", "tel:REDACTED FOR PRIVACY"],
|
||||
["tel", {"type":["fax"]}, "uri", "tel:REDACTED FOR PRIVACY"]
|
||||
["fn", {}, "text", ""]
|
||||
]
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"objectClassName":"entity",
|
||||
"handle":"REDACTED FOR PRIVACY",
|
||||
"handle":"",
|
||||
"remarks":[
|
||||
{
|
||||
"title":"REDACTED FOR PRIVACY",
|
||||
@@ -221,18 +217,14 @@
|
||||
"vcard",
|
||||
[
|
||||
["version", {}, "text", "4.0"],
|
||||
["fn", {}, "text", "REDACTED FOR PRIVACY"],
|
||||
["org", {}, "text", "REDACTED FOR PRIVACY"],
|
||||
["adr", {}, "text", ["", "", "REDACTED FOR PRIVACY", "REDACTED FOR PRIVACY", "REDACTED FOR PRIVACY", "REDACTED FOR PRIVACY", "XX"]],
|
||||
["tel", {"type":["voice"]}, "uri", "tel:REDACTED FOR PRIVACY"],
|
||||
["tel", {"type":["fax"]}, "uri", "tel:REDACTED FOR PRIVACY"]
|
||||
["fn", {}, "text", ""]
|
||||
]
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"objectClassName":"entity",
|
||||
"handle":"REDACTED FOR PRIVACY",
|
||||
"handle":"",
|
||||
"remarks":[
|
||||
{
|
||||
"title":"REDACTED FOR PRIVACY",
|
||||
@@ -262,11 +254,7 @@
|
||||
"vcard",
|
||||
[
|
||||
["version", {}, "text", "4.0"],
|
||||
["fn", {}, "text", "REDACTED FOR PRIVACY"],
|
||||
["org", {}, "text", "REDACTED FOR PRIVACY"],
|
||||
["adr", {}, "text", ["", "", "REDACTED FOR PRIVACY", "REDACTED FOR PRIVACY", "REDACTED FOR PRIVACY", "REDACTED FOR PRIVACY", "XX"]],
|
||||
["tel", {"type":["voice"]}, "uri", "tel:REDACTED FOR PRIVACY"],
|
||||
["tel", {"type":["fax"]}, "uri", "tel:REDACTED FOR PRIVACY"]
|
||||
["fn", {}, "text", ""]
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@
|
||||
},
|
||||
{
|
||||
"objectClassName": "entity",
|
||||
"handle": "REDACTED FOR PRIVACY",
|
||||
"handle": "",
|
||||
"roles":["administrative"],
|
||||
"remarks": [
|
||||
{
|
||||
@@ -183,18 +183,14 @@
|
||||
"vcard",
|
||||
[
|
||||
["version", {}, "text", "4.0"],
|
||||
["fn", {}, "text", "REDACTED FOR PRIVACY"],
|
||||
["org", {}, "text", "REDACTED FOR PRIVACY"],
|
||||
["adr", {}, "text", ["", "", "REDACTED FOR PRIVACY", "REDACTED FOR PRIVACY", "REDACTED FOR PRIVACY", "REDACTED FOR PRIVACY", "XX"]],
|
||||
["tel", {"type":["voice"]}, "uri", "tel:REDACTED FOR PRIVACY"],
|
||||
["tel", {"type":["fax"]}, "uri", "tel:REDACTED FOR PRIVACY"]
|
||||
["fn", {}, "text", ""]
|
||||
]
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"objectClassName":"entity",
|
||||
"handle":"REDACTED FOR PRIVACY",
|
||||
"handle":"",
|
||||
"remarks":[
|
||||
{
|
||||
"title":"REDACTED FOR PRIVACY",
|
||||
@@ -224,18 +220,13 @@
|
||||
"vcard",
|
||||
[
|
||||
["version", {}, "text", "4.0"],
|
||||
["fn", {}, "text", "REDACTED FOR PRIVACY"],
|
||||
["org", {}, "text", "REDACTED FOR PRIVACY"],
|
||||
["adr", {}, "text", ["", "", "REDACTED FOR PRIVACY", "REDACTED FOR PRIVACY", "REDACTED FOR PRIVACY", "REDACTED FOR PRIVACY", "XX"]],
|
||||
["tel", {"type":["voice"]}, "uri", "tel:REDACTED FOR PRIVACY"],
|
||||
["tel", {"type":["fax"]}, "uri", "tel:REDACTED FOR PRIVACY"]
|
||||
]
|
||||
["fn", {}, "text", ""] ]
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"objectClassName":"entity",
|
||||
"handle":"REDACTED FOR PRIVACY",
|
||||
"handle":"",
|
||||
"remarks":[
|
||||
{
|
||||
"title":"REDACTED FOR PRIVACY",
|
||||
@@ -265,11 +256,7 @@
|
||||
"vcard",
|
||||
[
|
||||
["version", {}, "text", "4.0"],
|
||||
["fn", {}, "text", "REDACTED FOR PRIVACY"],
|
||||
["org", {}, "text", "REDACTED FOR PRIVACY"],
|
||||
["adr", {}, "text", ["", "", "REDACTED FOR PRIVACY", "REDACTED FOR PRIVACY", "REDACTED FOR PRIVACY", "REDACTED FOR PRIVACY", "XX"]],
|
||||
["tel", {"type":["voice"]}, "uri", "tel:REDACTED FOR PRIVACY"],
|
||||
["tel", {"type":["fax"]}, "uri", "tel:REDACTED FOR PRIVACY"]
|
||||
["fn", {}, "text", ""]
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
@@ -156,12 +156,12 @@
|
||||
},
|
||||
{
|
||||
"title": "RDDS Inaccuracy Complaint Form",
|
||||
"description" : ["URL of the ICANN RDDS Inaccuracy Complaint Form: https://www.icann.org/wicf"],
|
||||
"description" : ["URL of the ICANN RDDS Inaccuracy Complaint Form: https://icann.org/wicf"],
|
||||
"links" :
|
||||
[
|
||||
{
|
||||
"rel" : "alternate",
|
||||
"href" : "https://www.icann.org/wicf",
|
||||
"href" : "https://icann.org/wicf",
|
||||
"type" : "text/html"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -137,12 +137,12 @@
|
||||
},
|
||||
{
|
||||
"title": "RDDS Inaccuracy Complaint Form",
|
||||
"description" : ["URL of the ICANN RDDS Inaccuracy Complaint Form: https://www.icann.org/wicf"],
|
||||
"description" : ["URL of the ICANN RDDS Inaccuracy Complaint Form: https://icann.org/wicf"],
|
||||
"links" :
|
||||
[
|
||||
{
|
||||
"rel" : "alternate",
|
||||
"href" : "https://www.icann.org/wicf",
|
||||
"href" : "https://icann.org/wicf",
|
||||
"type" : "text/html"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -157,12 +157,12 @@
|
||||
},
|
||||
{
|
||||
"title": "RDDS Inaccuracy Complaint Form",
|
||||
"description" : ["URL of the ICANN RDDS Inaccuracy Complaint Form: https://www.icann.org/wicf"],
|
||||
"description" : ["URL of the ICANN RDDS Inaccuracy Complaint Form: https://icann.org/wicf"],
|
||||
"links" :
|
||||
[
|
||||
{
|
||||
"rel" : "alternate",
|
||||
"href" : "https://www.icann.org/wicf",
|
||||
"href" : "https://icann.org/wicf",
|
||||
"type" : "text/html"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -95,12 +95,12 @@
|
||||
},
|
||||
{
|
||||
"title": "RDDS Inaccuracy Complaint Form",
|
||||
"description": ["URL of the ICANN RDDS Inaccuracy Complaint Form: https://www.icann.org/wicf"],
|
||||
"description": ["URL of the ICANN RDDS Inaccuracy Complaint Form: https://icann.org/wicf"],
|
||||
"links":
|
||||
[
|
||||
{
|
||||
"rel": "alternate",
|
||||
"href": "https://www.icann.org/wicf",
|
||||
"href": "https://icann.org/wicf",
|
||||
"type": "text/html"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -130,12 +130,12 @@
|
||||
},
|
||||
{
|
||||
"title": "RDDS Inaccuracy Complaint Form",
|
||||
"description": ["URL of the ICANN RDDS Inaccuracy Complaint Form: https://www.icann.org/wicf"],
|
||||
"description": ["URL of the ICANN RDDS Inaccuracy Complaint Form: https://icann.org/wicf"],
|
||||
"links":
|
||||
[
|
||||
{
|
||||
"rel":"alternate",
|
||||
"href":"https://www.icann.org/wicf",
|
||||
"href":"https://icann.org/wicf",
|
||||
"type":"text/html"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -98,12 +98,12 @@
|
||||
},
|
||||
{
|
||||
"title": "RDDS Inaccuracy Complaint Form",
|
||||
"description":["URL of the ICANN RDDS Inaccuracy Complaint Form: https://www.icann.org/wicf"],
|
||||
"description":["URL of the ICANN RDDS Inaccuracy Complaint Form: https://icann.org/wicf"],
|
||||
"links":[
|
||||
{
|
||||
"type":"text/html",
|
||||
"rel":"alternate",
|
||||
"href":"https://www.icann.org/wicf"
|
||||
"href":"https://icann.org/wicf"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -144,12 +144,12 @@
|
||||
},
|
||||
{
|
||||
"title": "RDDS Inaccuracy Complaint Form",
|
||||
"description" : ["URL of the ICANN RDDS Inaccuracy Complaint Form: https://www.icann.org/wicf"],
|
||||
"description" : ["URL of the ICANN RDDS Inaccuracy Complaint Form: https://icann.org/wicf"],
|
||||
"links" :
|
||||
[
|
||||
{
|
||||
"rel" : "alternate",
|
||||
"href" : "https://www.icann.org/wicf",
|
||||
"href" : "https://icann.org/wicf",
|
||||
"type" : "text/html"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
},
|
||||
{
|
||||
"objectClassName": "entity",
|
||||
"handle": "REDACTED FOR PRIVACY",
|
||||
"handle": "",
|
||||
"roles": ["administrative"],
|
||||
"remarks": [
|
||||
{
|
||||
@@ -166,31 +166,14 @@
|
||||
"vcardArray": [
|
||||
"vcard",
|
||||
[
|
||||
["version",{},"text","4.0"],
|
||||
["fn",{},"text","REDACTED FOR PRIVACY"],
|
||||
["org",{},"text","REDACTED FOR PRIVACY"],
|
||||
[
|
||||
"adr",
|
||||
{},
|
||||
"text",
|
||||
[
|
||||
"",
|
||||
"",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"XX"
|
||||
]
|
||||
],
|
||||
["tel",{"type":["voice"]},"uri","tel:REDACTED FOR PRIVACY"],
|
||||
["tel",{"type":["fax"]},"uri","tel:REDACTED FOR PRIVACY"]
|
||||
["version", {}, "text", "4.0"],
|
||||
["fn", {}, "text", ""]
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"objectClassName": "entity",
|
||||
"handle": "REDACTED FOR PRIVACY",
|
||||
"handle": "",
|
||||
"roles": ["technical"],
|
||||
"remarks": [
|
||||
{
|
||||
@@ -219,31 +202,14 @@
|
||||
"vcardArray": [
|
||||
"vcard",
|
||||
[
|
||||
["version",{},"text","4.0"],
|
||||
["fn",{},"text","REDACTED FOR PRIVACY"],
|
||||
["org",{},"text","REDACTED FOR PRIVACY"],
|
||||
[
|
||||
"adr",
|
||||
{},
|
||||
"text",
|
||||
[
|
||||
"",
|
||||
"",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"XX"
|
||||
]
|
||||
],
|
||||
["tel",{"type":["voice"]},"uri","tel:REDACTED FOR PRIVACY"],
|
||||
["tel",{"type":["fax"]},"uri","tel:REDACTED FOR PRIVACY"]
|
||||
["version", {}, "text", "4.0"],
|
||||
["fn", {}, "text", ""]
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"objectClassName": "entity",
|
||||
"handle": "REDACTED FOR PRIVACY",
|
||||
"handle": "",
|
||||
"roles": ["registrant"],
|
||||
"remarks": [
|
||||
{
|
||||
@@ -272,25 +238,8 @@
|
||||
"vcardArray": [
|
||||
"vcard",
|
||||
[
|
||||
["version",{},"text","4.0"],
|
||||
["fn",{},"text","REDACTED FOR PRIVACY"],
|
||||
["org",{},"text","REDACTED FOR PRIVACY"],
|
||||
[
|
||||
"adr",
|
||||
{},
|
||||
"text",
|
||||
[
|
||||
"",
|
||||
"",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"XX"
|
||||
]
|
||||
],
|
||||
["tel",{"type":["voice"]},"uri","tel:REDACTED FOR PRIVACY"],
|
||||
["tel",{"type":["fax"]},"uri","tel:REDACTED FOR PRIVACY"]
|
||||
["version", {}, "text", "4.0"],
|
||||
["fn", {}, "text", ""]
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"objectClassName" : "entity",
|
||||
"handle" : "REDACTED FOR PRIVACY",
|
||||
"handle" : "",
|
||||
"roles" : ["registrant"],
|
||||
"events": [
|
||||
{
|
||||
@@ -11,25 +11,8 @@
|
||||
"vcardArray": [
|
||||
"vcard",
|
||||
[
|
||||
["version",{},"text","4.0"],
|
||||
["fn",{},"text","REDACTED FOR PRIVACY"],
|
||||
["org",{},"text","REDACTED FOR PRIVACY"],
|
||||
[
|
||||
"adr",
|
||||
{},
|
||||
"text",
|
||||
[
|
||||
"",
|
||||
"",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"REDACTED FOR PRIVACY",
|
||||
"XX"
|
||||
]
|
||||
],
|
||||
["tel",{"type":["voice"]},"uri","tel:REDACTED FOR PRIVACY"],
|
||||
["tel",{"type":["fax"]},"uri","tel:REDACTED FOR PRIVACY"]
|
||||
["version", {}, "text", "4.0"],
|
||||
["fn", {}, "text", ""]
|
||||
]
|
||||
],
|
||||
"remarks": [
|
||||
|
||||
@@ -59,12 +59,12 @@
|
||||
},
|
||||
{
|
||||
"title": "RDDS Inaccuracy Complaint Form",
|
||||
"description": ["URL of the ICANN RDDS Inaccuracy Complaint Form: https://www.icann.org/wicf"],
|
||||
"description": ["URL of the ICANN RDDS Inaccuracy Complaint Form: https://icann.org/wicf"],
|
||||
"links":
|
||||
[
|
||||
{
|
||||
"rel": "alternate",
|
||||
"href": "https://www.icann.org/wicf",
|
||||
"href": "https://icann.org/wicf",
|
||||
"type": "text/html"
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user