Delete end-date sunrise, landrush, and sunrush phases

This also deletes the associated commands and domain application specific
entities.

We haven't used any of these TLD phases since early 2015 and have no
intent to do so in the future, so it makes sense to delete them now so we
don't have to carry them through the Registry 3.0 migration.

Note that, while there are data model changes, there should be no required
data migrations. The fields and entities being removed will simply remain
as orphans. I confirmed that the removed types (such as the SUNRUSH_ADD
GracePeriodType) are no longer used in production data, and left types
that are still used, e.g. BillingEvent.Flag.LANDRUSH or
HistoryEntry.Type.ALLOCATE.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=228752843
This commit is contained in:
mcilwain 2019-01-10 12:09:14 -08:00 committed by Ben McIlwain
parent c74ffd7559
commit 580302898d
282 changed files with 344 additions and 17634 deletions

View file

@ -1,190 +0,0 @@
// Copyright 2017 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.tools;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Strings.emptyToNull;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.io.BaseEncoding.base16;
import static google.registry.model.eppcommon.EppXmlTransformer.unmarshal;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.tools.CommandUtilities.addHeader;
import static java.util.stream.Collectors.joining;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.base.Ascii;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.template.soy.data.SoyMapData;
import com.googlecode.objectify.Key;
import google.registry.model.domain.DesignatedContact;
import google.registry.model.domain.DomainApplication;
import google.registry.model.domain.DomainCommand;
import google.registry.model.domain.Period;
import google.registry.model.domain.launch.ApplicationStatus;
import google.registry.model.domain.launch.LaunchNotice;
import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.EppInput.ResourceCommandWrapper;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.smd.SignedMark;
import google.registry.tools.soy.DomainAllocateSoyInfo;
import google.registry.xml.XmlException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/** Command to allocated a domain from a domain application. */
@Parameters(separators = " =", commandDescription = "Allocate a domain application")
final class AllocateDomainCommand extends MutatingEppToolCommand {
@Parameter(
names = "--ids",
description = "Comma-delimited list of application IDs to update.",
required = true)
String ids;
private final List<Key<DomainApplication>> applicationKeys = new ArrayList<>();
@Override
protected String postExecute() {
return ofy()
.transactNewReadOnly(
() -> {
String failureMessage =
ofy()
.load()
.keys(applicationKeys)
.values()
.stream()
.map(
application ->
application.getApplicationStatus()
== ApplicationStatus.ALLOCATED
? null
: application.getFullyQualifiedDomainName())
.filter(Objects::nonNull)
.collect(joining("\n"));
return failureMessage.isEmpty()
? "ALL SUCCEEDED"
: addHeader("FAILURES", failureMessage);
});
}
/** Extract the registration period from the XML used to create the domain application. */
private static Period extractPeriodFromXml(byte[] xmlBytes) throws XmlException {
EppInput eppInput = unmarshal(EppInput.class, xmlBytes);
return ((DomainCommand.Create)
((ResourceCommandWrapper) eppInput.getCommandWrapper().getCommand())
.getResourceCommand()).getPeriod();
}
@Override
protected void initMutatingEppToolCommand() {
checkArgument(superuser, "This command MUST be run as --superuser.");
setSoyTemplate(DomainAllocateSoyInfo.getInstance(), DomainAllocateSoyInfo.CREATE);
ofy().transactNewReadOnly(this::initAllocateDomainCommand);
}
private void initAllocateDomainCommand() {
Iterable<Key<DomainApplication>> keys =
transform(
Splitter.on(',').split(ids),
applicationId -> Key.create(DomainApplication.class, applicationId));
for (DomainApplication application : ofy().load().keys(keys).values()) {
// If the application is already allocated print a warning but do not fail.
if (application.getApplicationStatus() == ApplicationStatus.ALLOCATED) {
System.err.printf("Application %s has already been allocated\n", application.getRepoId());
continue;
}
// Ensure domain doesn't already have a final status which it shouldn't be updated
// from.
checkState(
!application.getApplicationStatus().isFinalStatus(),
"Application has final status %s",
application.getApplicationStatus());
try {
HistoryEntry history =
checkNotNull(
ofy()
.load()
.type(HistoryEntry.class)
.ancestor(checkNotNull(application))
.order("modificationTime")
.first()
.now(),
"Could not find any history entries for domain application %s",
application.getRepoId());
String clientTransactionId =
emptyToNull(history.getTrid().getClientTransactionId().orElse(null));
Period period = checkNotNull(extractPeriodFromXml(history.getXmlBytes()));
checkArgument(period.getUnit() == Period.Unit.YEARS);
ImmutableMap.Builder<String, String> contactsMapBuilder = new ImmutableMap.Builder<>();
for (DesignatedContact contact : application.getContacts()) {
contactsMapBuilder.put(
Ascii.toLowerCase(contact.getType().toString()),
ofy().load().key(contact.getContactKey()).now().getForeignKey());
}
LaunchNotice launchNotice = application.getLaunchNotice();
String smdId =
application.getEncodedSignedMarks().isEmpty()
? null
: unmarshal(SignedMark.class, application.getEncodedSignedMarks().get(0).getBytes())
.getId();
ImmutableMap<String, String> launchNoticeMap =
(launchNotice == null)
? null
: ImmutableMap.of(
"noticeId", launchNotice.getNoticeId().getTcnId(),
"expirationTime", launchNotice.getExpirationTime().toString(),
"acceptedTime", launchNotice.getAcceptedTime().toString());
ImmutableList<ImmutableMap<String, ?>> dsRecords =
application
.getDsData()
.stream()
.map(
dsData ->
ImmutableMap.of(
"keyTag", dsData.getKeyTag(),
"algorithm", dsData.getAlgorithm(),
"digestType", dsData.getDigestType(),
"digest", base16().encode(dsData.getDigest())))
.collect(toImmutableList());
addSoyRecord(
application.getCurrentSponsorClientId(),
new SoyMapData(
"name", application.getFullyQualifiedDomainName(),
"period", period.getValue(),
"nameservers", application.loadNameserverFullyQualifiedHostNames(),
"registrant", ofy().load().key(application.getRegistrant()).now().getForeignKey(),
"contacts", contactsMapBuilder.build(),
"authInfo", application.getAuthInfo().getPw().getValue(),
"smdId", smdId,
"applicationRoid", application.getRepoId(),
"applicationTime", application.getCreationTime().toString(),
"launchNotice", launchNoticeMap,
"dsRecords", dsRecords,
"clTrid", clientTransactionId));
applicationKeys.add(Key.create(application));
} catch (XmlException e) {
throw new RuntimeException(e);
}
}
}
}

View file

@ -18,11 +18,9 @@ import static com.google.common.base.Preconditions.checkState;
import com.google.common.base.Ascii;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.googlecode.objectify.Key;
import google.registry.model.EppResource;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainApplication;
import google.registry.model.domain.DomainResource;
import google.registry.model.host.HostResource;
import google.registry.model.index.ForeignKeyIndex;
@ -33,21 +31,18 @@ class CommandUtilities {
/** A useful parameter enum for commands that operate on {@link EppResource} objects. */
public enum ResourceType {
CONTACT,
HOST,
DOMAIN,
APPLICATION;
CONTACT(ContactResource.class),
HOST(HostResource.class),
DOMAIN(DomainResource.class);
private Class<? extends EppResource> clazz;
ResourceType(Class<? extends EppResource> clazz) {
this.clazz = clazz;
}
public Key<? extends EppResource> getKey(String uniqueId, DateTime now) {
return this == APPLICATION
? Key.create(DomainApplication.class, uniqueId)
: ForeignKeyIndex.loadAndGetKey(
ImmutableMap.of(
CONTACT, ContactResource.class,
HOST, HostResource.class,
DOMAIN, DomainResource.class).get(this),
uniqueId,
now);
return ForeignKeyIndex.loadAndGetKey(clazz, uniqueId, now);
}
}

View file

@ -74,12 +74,6 @@ abstract class CreateOrUpdateTldCommand extends MutatingCommand {
description = "Length of the add grace period (in ISO 8601 duration format)")
Duration addGracePeriod;
@Nullable
@Parameter(
names = "--sunrush_add_grace_period",
description = "Length of the add grace period during sunrush (in ISO 8601 duration format)")
Duration sunrushAddGracePeriod;
@Nullable
@Parameter(
names = "--redemption_grace_period",
@ -331,7 +325,6 @@ abstract class CreateOrUpdateTldCommand extends MutatingCommand {
}
Optional.ofNullable(addGracePeriod).ifPresent(builder::setAddGracePeriodLength);
Optional.ofNullable(sunrushAddGracePeriod).ifPresent(builder::setSunrushAddGracePeriodLength);
Optional.ofNullable(redemptionGracePeriod).ifPresent(builder::setRedemptionGracePeriodLength);
Optional.ofNullable(pendingDeleteLength).ifPresent(builder::setPendingDeleteLength);
Optional.ofNullable(automaticTransferLength).ifPresent(builder::setAutomaticTransferLength);

View file

@ -1,68 +0,0 @@
// Copyright 2017 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.tools;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.base.Ascii;
import com.google.template.soy.data.SoyMapData;
import google.registry.model.domain.launch.LaunchPhase;
import google.registry.tools.soy.DomainApplicationInfoSoyInfo;
/** A command to execute a domain application info EPP command. */
@Parameters(separators = " =", commandDescription = "Get domain application EPP info")
final class DomainApplicationInfoCommand extends NonMutatingEppToolCommand {
@Parameter(
names = {"-c", "--client"},
description = "Client identifier of the registrar to execute the command as",
required = true)
String clientId;
@Parameter(
names = {"--id"},
description = "ID of the application.",
required = true)
private String id;
@Parameter(
names = {"-n", "--domain_name"},
description = "Domain name to query.",
required = true)
private String domainName;
@Parameter(
names = {"--phase"},
description = "Phase of the application to query.",
required = true)
private String phase;
@Override
void initEppToolCommand() {
LaunchPhase launchPhase = checkArgumentNotNull(
LaunchPhase.fromValue(Ascii.toLowerCase(phase)), "Illegal launch phase.");
setSoyTemplate(
DomainApplicationInfoSoyInfo.getInstance(),
DomainApplicationInfoSoyInfo.DOMAINAPPLICATIONINFO);
addSoyRecord(clientId, new SoyMapData(
"domainName", domainName,
"id", id,
"phase", launchPhase.getPhase(),
"subphase", launchPhase.getSubphase()));
}
}

View file

@ -1,176 +0,0 @@
// Copyright 2017 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.tools;
import static com.google.common.base.Strings.isNullOrEmpty;
import static google.registry.model.eppcommon.EppXmlTransformer.unmarshal;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.model.registry.Registries.assertTldExists;
import static google.registry.util.DateTimeUtils.isBeforeOrAt;
import static google.registry.util.DomainNameUtils.ACE_PREFIX;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Collections.emptyList;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.base.Joiner;
import com.google.common.net.InternetDomainName;
import com.googlecode.objectify.cmd.LoadType;
import com.googlecode.objectify.cmd.Query;
import google.registry.model.domain.DomainApplication;
import google.registry.model.smd.EncodedSignedMark;
import google.registry.model.smd.SignedMark;
import google.registry.model.smd.SignedMarkRevocationList;
import google.registry.model.tmch.ClaimsListShard;
import google.registry.tmch.TmchXmlSignature;
import google.registry.tools.params.PathParameter;
import google.registry.util.Clock;
import google.registry.util.Idn;
import google.registry.xml.XmlException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import javax.annotation.CheckReturnValue;
import javax.inject.Inject;
import org.joda.time.DateTime;
/** Command to generate a report of all domain applications. */
@Parameters(separators = " =", commandDescription = "Generate report of all domain applications.")
final class GenerateApplicationsReportCommand implements CommandWithRemoteApi {
@Parameter(
names = {"-t", "--tld"},
description = "TLD which contains the applications.")
private String tld;
@Parameter(
names = "--ids",
description = "Comma-delimited list of application IDs to include. "
+ "If not provided, all active application will be included.")
private List<Long> ids = emptyList();
@Parameter(
names = {"-o", "--output"},
description = "Output file.",
validateWith = PathParameter.OutputFile.class)
private Path output = Paths.get("/dev/stdout");
@Inject Clock clock;
@Inject TmchXmlSignature tmchXmlSignature;
@Override
public void run() throws Exception {
if (tld != null) {
assertTldExists(tld);
}
DateTime now = clock.nowUtc();
List<String> result = new ArrayList<>();
if (!ids.isEmpty()) {
for (Long applicationId : ids) {
DomainApplication domainApplication = ofy().load()
.type(DomainApplication.class)
.id(applicationId)
.now();
if (domainApplication == null) {
System.err.printf("Application ID %d not found\n", applicationId);
continue;
}
validate(domainApplication, now).ifPresent(result::add);
}
} else {
LoadType<DomainApplication> loader = ofy().load().type(DomainApplication.class);
Query<DomainApplication> domainApplications =
(tld == null) ? loader : loader.filter("tld", tld);
for (DomainApplication domainApplication : domainApplications) {
validate(domainApplication, now).ifPresent(result::add);
}
}
Files.write(output, result, UTF_8);
}
/** Processes a domain application and adds report lines to {@code result}. */
Optional<String> validate(DomainApplication domainApplication, DateTime now) {
// Validate the label.
List<String> nameParts =
InternetDomainName.from(domainApplication.getFullyQualifiedDomainName()).parts();
String label = nameParts.get(0);
// Ignore deleted applications.
if (isBeforeOrAt(domainApplication.getDeletionTime(), now)) {
return Optional.empty();
}
// Defensive invalid punycode check.
if (label.startsWith(ACE_PREFIX) && label.equals(Idn.toUnicode(label))) {
return Optional.of(makeLine(domainApplication, "Invalid punycode"));
}
// Validate the SMD.
for (EncodedSignedMark encodedSignedMark : domainApplication.getEncodedSignedMarks()) {
byte[] signedMarkData;
try {
signedMarkData = encodedSignedMark.getBytes();
} catch (IllegalStateException e) {
return Optional.of(makeLine(domainApplication, "Incorrectly encoded SMD data"));
}
SignedMark signedMark;
try {
signedMark = unmarshal(SignedMark.class, signedMarkData);
} catch (XmlException e) {
return Optional.of(makeLine(domainApplication, "Unparseable SMD"));
}
if (SignedMarkRevocationList.get().isSmdRevoked(signedMark.getId(),
domainApplication.getCreationTime())) {
return Optional.of(makeLine(domainApplication, "SMD revoked"));
}
try {
tmchXmlSignature.verify(signedMarkData);
} catch (Exception e) {
return Optional.of(
makeLine(domainApplication, String.format("Invalid SMD (%s)", e.getMessage())));
}
}
// If this is a landrush application and has no claims notice, check to see if it should have
// one.
if (domainApplication.getEncodedSignedMarks().isEmpty()
&& (domainApplication.getLaunchNotice() == null
|| domainApplication.getLaunchNotice().getNoticeId() == null
|| isNullOrEmpty(domainApplication.getLaunchNotice().getNoticeId().getTcnId()))
&& ClaimsListShard.get().getClaimKey(label).isPresent()) {
return Optional.of(makeLine(domainApplication, "Missing claims notice"));
}
return Optional.of(makeLine(domainApplication, "Valid"));
}
@CheckReturnValue
private String makeLine(DomainApplication domainApplication, String validityMessage) {
return Joiner.on(',').join(
domainApplication.getRepoId(),
domainApplication.getFullyQualifiedDomainName(),
domainApplication.getEncodedSignedMarks().isEmpty() ? "landrush" : "sunrise",
domainApplication.getApplicationStatus(),
domainApplication.getCurrentSponsorClientId(),
ofy().load().key(domainApplication.getRegistrant()).now().getEmailAddress(),
validityMessage);
}
}

View file

@ -1,259 +0,0 @@
// Copyright 2017 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.tools;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Strings.nullToEmpty;
import static google.registry.model.domain.launch.ApplicationStatus.REJECTED;
import static google.registry.model.domain.launch.ApplicationStatus.VALIDATED;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.model.registry.Registries.assertTldExists;
import static google.registry.util.DateTimeUtils.isAtOrAfter;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.joining;
import static org.joda.time.DateTimeZone.UTC;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import com.google.common.collect.Ordering;
import com.google.common.collect.TreeMultimap;
import google.registry.model.contact.ContactAddress;
import google.registry.model.contact.ContactPhoneNumber;
import google.registry.model.contact.ContactResource;
import google.registry.model.contact.PostalInfo;
import google.registry.model.domain.DomainApplication;
import google.registry.model.domain.launch.ApplicationStatus;
import google.registry.model.eppcommon.Address;
import google.registry.model.eppcommon.PhoneNumber;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registrar.RegistrarContact;
import google.registry.tools.params.PathParameter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
/** Command to generate the auction data for a TLD. */
@Parameters(separators = " =", commandDescription = "Generate auction data")
final class GenerateAuctionDataCommand implements CommandWithRemoteApi {
@Parameter(
description = "TLD(s) to generate auction data for",
required = true)
private List<String> mainParameters;
@Parameter(
names = {"-o", "--output"},
description = "Output file.",
validateWith = PathParameter.OutputFile.class)
private Path output = Paths.get("/dev/stdout");
@Parameter(
names = "--skip_validated_check",
description = "Skip the check that all contended applications are already validated.")
private boolean skipValidatedCheck;
/** This is the date format expected in the output file. */
final DateTimeFormatter formatter = DateTimeFormat.forPattern("YYYY-MM-dd HH:mm:ss");
@Override
public void run() throws Exception {
checkArgument(mainParameters.size() == 1,
"Expected a single parameter with the TLD name. Actual: %s",
Joiner.on(' ').join(mainParameters));
String tld = mainParameters.get(0);
assertTldExists(tld);
List<String> result = new ArrayList<>();
Set<String> registrars = new TreeSet<>();
for (Map.Entry<String, Collection<DomainApplication>> entry :
getDomainApplicationMap(tld).asMap().entrySet()) {
String domainName = entry.getKey();
List<DomainApplication> domainApplications = filterApplications(entry.getValue());
// Skip the domain if there are no contentions. This can happen if there is only a single
// sunrise applicant, or if there are no sunrise applicants and just a single landrush
// application.
if (domainApplications.size() < 2) {
continue;
}
Set<String> emailAddresses = new HashSet<>();
for (DomainApplication domainApplication : domainApplications) {
checkState(skipValidatedCheck || domainApplication.getApplicationStatus() == VALIDATED, ""
+ "Can't process contending applications for %s because some applications "
+ "are not yet validated.", domainName);
ContactResource registrant =
ofy().load().key(checkNotNull(domainApplication.getRegistrant())).now();
result.add(emitApplication(domainApplication, registrant));
// Ensure the registrant's email address is unique across the contending applications.
if (!emailAddresses.add(registrant.getEmailAddress())) {
System.err.printf(
"Warning: Multiple applications found with email address %s for domain %s\n",
registrant.getEmailAddress(),
domainName);
}
// Add registrar for this application our set of registrars that we must output at the end.
registrars.add(domainApplication.getCurrentSponsorClientId());
}
}
// Output records for the registrars of any applications we emitted above.
for (String clientId : registrars) {
Optional<Registrar> registrar = Registrar.loadByClientId(clientId);
checkState(registrar.isPresent(), "Registrar %s does not exist", clientId);
result.add(emitRegistrar(registrar.get()));
}
Files.write(output, result, UTF_8);
}
/** Return a map of all fully-qualified domain names mapped to the applications for that name. */
private static Multimap<String, DomainApplication> getDomainApplicationMap(final String tld) {
DateTime now = DateTime.now(UTC);
Multimap<String, DomainApplication> domainApplicationMap =
TreeMultimap.create(Ordering.natural(), comparing(DomainApplication::getForeignKey));
Iterable<DomainApplication> domainApplications =
ofy().load().type(DomainApplication.class).filter("tld", tld);
for (DomainApplication domainApplication : domainApplications) {
// Ignore deleted and rejected applications. They aren't under consideration.
ApplicationStatus applicationStatus = domainApplication.getApplicationStatus();
DateTime deletionTime = domainApplication.getDeletionTime();
if (applicationStatus == REJECTED || isAtOrAfter(now, deletionTime)) {
continue;
}
boolean result = domainApplicationMap.put(
domainApplication.getFullyQualifiedDomainName(), domainApplication);
checkState(result, "Domain application not added to map: %s", domainApplication);
}
return domainApplicationMap;
}
/**
* Filter applications by their priority. If there are any sunrise applications, then those will
* be returned; otherwise just the landrush applications will be returned.
*/
private static List<DomainApplication> filterApplications(
Iterable<DomainApplication> domainApplications) {
// Sort the applications into sunrise and landrush applications.
List<DomainApplication> sunriseApplications = new ArrayList<>();
List<DomainApplication> landrushApplications = new ArrayList<>();
for (DomainApplication domainApplication : domainApplications) {
if (!domainApplication.getEncodedSignedMarks().isEmpty()) {
sunriseApplications.add(domainApplication);
} else {
landrushApplications.add(domainApplication);
}
}
return !sunriseApplications.isEmpty() ? sunriseApplications : landrushApplications;
}
/** Return a record line for the given application. */
private String emitApplication(DomainApplication domainApplication, ContactResource registrant) {
Optional<PostalInfo> postalInfo =
Optional.ofNullable(
Optional.ofNullable(registrant.getInternationalizedPostalInfo())
.orElse(registrant.getLocalizedPostalInfo()));
Optional<ContactAddress> address =
Optional.ofNullable(postalInfo.map(PostalInfo::getAddress).orElse(null));
List<String> street = address.map(Address::getStreet).orElseGet(ImmutableList::of);
Optional<ContactPhoneNumber> phoneNumber = Optional.ofNullable(registrant.getVoiceNumber());
// Each line containing an auction participant has the following format:
//
// Domain|Application ID|Application timestamp|Last update date|Registrar Name|
// Registrant Name|Registrant Company|Registrant Address 1|Registrant Address 2|
// Registrant City|Registrant Province|Registrant Postal Code|Registrant Country|
// Registrant Email|Registrant Telephone|Reserve|Application Type
return Joiner.on('|')
.join(
ImmutableList.of(
domainApplication.getFullyQualifiedDomainName(),
domainApplication.getForeignKey(),
formatter.print(domainApplication.getCreationTime()),
domainApplication.getLastEppUpdateTime() != null
? formatter.print(domainApplication.getLastEppUpdateTime())
: "",
domainApplication.getCurrentSponsorClientId(),
nullToEmpty(postalInfo.map(PostalInfo::getName).orElse("")),
nullToEmpty(postalInfo.map(PostalInfo::getOrg).orElse("")),
Iterables.getFirst(street, ""),
street.stream().skip(1).filter(Objects::nonNull).collect(joining(" ")),
nullToEmpty(address.map(Address::getCity).orElse("")),
nullToEmpty(address.map(Address::getState).orElse("")),
nullToEmpty(address.map(Address::getZip).orElse("")),
nullToEmpty(address.map(Address::getCountryCode).orElse("")),
nullToEmpty(registrant.getEmailAddress()),
nullToEmpty(phoneNumber.map(PhoneNumber::toPhoneString).orElse("")),
"",
domainApplication.getEncodedSignedMarks().isEmpty() ? "Landrush" : "Sunrise"));
}
/** Return a record line for the given registrar. */
private static String emitRegistrar(Registrar registrar) {
// TODO(b/19016140): Determine if this set-up is required.
Optional<RegistrarContact> contact =
Optional.ofNullable(Iterables.getFirst(registrar.getContacts(), null));
Optional<RegistrarAddress> address =
Optional.ofNullable(
Optional.ofNullable(registrar.getLocalizedAddress())
.orElse(registrar.getInternationalizedAddress()));
List<String> street = address.map(Address::getStreet).orElseGet(ImmutableList::of);
// Each line containing the registrar of an auction participant has the following format:
//
// Registrar Name|Registrar Contact Name|Registrar Full Company|Registrar Address 1|
// Registrar Address 2|Registrar City|Registrar Province|Registrar Postal Code|
// Registrar Country|Registrar Email|Registrar Telephone
return Joiner.on('|').join(ImmutableList.of(
registrar.getClientId(),
contact.map(RegistrarContact::getName).orElse("N/A"),
nullToEmpty(registrar.getRegistrarName()),
Iterables.getFirst(street, ""),
Iterables.get(street, 1, ""),
address.map(registrarAddress -> nullToEmpty(registrarAddress.getCity())).orElse(""),
address.map(registrarAddress1 ->
nullToEmpty(registrarAddress1.getState())).orElse(""),
address.map(registrarAddress2 -> nullToEmpty(registrarAddress2.getZip())).orElse(""),
address.map(registrarAddress3 ->
nullToEmpty(registrarAddress3.getCountryCode())).orElse(""),
nullToEmpty(registrar.getEmailAddress()),
nullToEmpty(registrar.getPhoneNumber())));
}
}

View file

@ -1,37 +0,0 @@
// Copyright 2017 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.tools;
import static google.registry.model.EppResourceUtils.loadDomainApplication;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import java.util.List;
/** Command to show a domain application. */
@Parameters(separators = " =", commandDescription = "Show domain application resource(s)")
final class GetApplicationCommand extends GetEppResourceCommand {
@Parameter(
description = "Domain application id(s)",
required = true)
private List<String> mainParameters;
@Override
public void runAndPrint() {
mainParameters.forEach(
appId -> printResource("Application", appId, loadDomainApplication(appId, readTimestamp)));
}
}

View file

@ -1,67 +0,0 @@
// Copyright 2017 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.tools;
import static google.registry.model.index.DomainApplicationIndex.loadActiveApplicationsByDomainName;
import static google.registry.model.registry.Registries.assertTldExists;
import static google.registry.model.registry.Registries.findTldForNameOrThrow;
import static org.joda.time.DateTimeZone.UTC;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.collect.ImmutableList;
import com.google.common.net.InternetDomainName;
import google.registry.model.domain.DomainApplication;
import java.util.List;
import org.joda.time.DateTime;
/** Command to generate a list of all applications for a given domain name(s). */
@Parameters(separators = " =",
commandDescription = "Generate list of application IDs and sponsors for given domain name(s)")
final class GetApplicationIdsCommand implements CommandWithRemoteApi {
@Parameter(
description = "Fully qualified domain name(s)",
required = true)
private List<String> mainParameters;
@Override
public void run() {
for (String domainName : mainParameters) {
InternetDomainName tld = findTldForNameOrThrow(InternetDomainName.from(domainName));
assertTldExists(tld.toString());
System.out.printf("%s:%n", domainName);
// Sample output:
// example.tld:
// 1 (NewRegistrar)
// 2 (OtherRegistrar)
// example2.tld:
// No applications exist for 'example2.tld'.
ImmutableList<DomainApplication> applications = ImmutableList.copyOf(
loadActiveApplicationsByDomainName(domainName, DateTime.now(UTC)));
if (applications.isEmpty()) {
System.out.printf(" No applications exist for \'%s\'.%n", domainName);
} else {
for (DomainApplication application : applications) {
System.out.printf(
" %s (%s)%n",
application.getForeignKey(),
application.getCurrentSponsorClientId());
}
}
}
}
}

View file

@ -1,92 +0,0 @@
// Copyright 2017 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.tools;
import static google.registry.model.domain.launch.ApplicationStatus.REJECTED;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.model.registry.Registries.assertTldExists;
import static google.registry.util.DateTimeUtils.isAtOrAfter;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.beust.jcommander.internal.Sets;
import com.google.common.base.Ascii;
import google.registry.model.domain.DomainApplication;
import google.registry.model.domain.launch.ApplicationStatus;
import google.registry.tools.params.PathParameter;
import google.registry.util.Idn;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.joda.time.DateTime;
/** Command to generate a list of all slds in a tld that have open applications. */
@Parameters(separators = " =", commandDescription = "Generate applied-for domains list")
final class GetAppliedLabelsCommand implements CommandWithRemoteApi {
@Parameter(
names = {"-t", "--tld"},
description = "TLD to generate list for.",
required = true)
private String tld;
@Parameter(
names = {"-o", "--output"},
description = "Output file.",
validateWith = PathParameter.OutputFile.class)
private Path output = Paths.get("/dev/stdout");
@Override
public void run() throws Exception {
List<String> lines = new ArrayList<>();
for (String label : getDomainApplicationMap(assertTldExists(tld))) {
label = label.substring(0, label.lastIndexOf('.'));
try {
lines.add(Idn.toUnicode(Ascii.toLowerCase(label)));
} catch (IllegalArgumentException e) {
// An invalid punycode label that we need to reject later.
lines.add(label + " (invalid)");
}
}
Files.write(output, lines, UTF_8);
}
/** Return a set of all fully-qualified domain names with open applications. */
private static Set<String> getDomainApplicationMap(final String tld) {
return ofy()
.transact(
() -> {
Set<String> labels = Sets.newHashSet();
List<DomainApplication> domainApplications;
domainApplications =
ofy().load().type(DomainApplication.class).filter("tld", tld).list();
for (DomainApplication domainApplication : domainApplications) {
// Ignore deleted and rejected applications. They aren't under consideration.
ApplicationStatus applicationStatus = domainApplication.getApplicationStatus();
DateTime deletionTime = domainApplication.getDeletionTime();
if (applicationStatus == REJECTED
|| isAtOrAfter(ofy().getTransactionTime(), deletionTime)) {
continue;
}
labels.add(domainApplication.getFullyQualifiedDomainName());
}
return labels;
});
}
}

View file

@ -52,7 +52,7 @@ final class GetHistoryEntriesCommand implements CommandWithRemoteApi {
@Parameter(
names = "--id",
description = "Foreign key of the resource, or application ID of the domain application.")
description = "Foreign key of the resource.")
private String uniqueId;
@Override

View file

@ -39,13 +39,7 @@ public final class GtechTool {
"create_registrar_groups",
"create_sandbox_tld",
"delete_domain",
"domain_application_info",
"generate_applications_report",
"generate_auction_data",
"generate_dns_report",
"get_application",
"get_application_ids",
"get_applied_labels",
"get_claims_list",
"get_contact",
"get_domain",

View file

@ -29,7 +29,6 @@ public final class RegistryTool {
*/
public static final ImmutableMap<String, Class<? extends Command>> COMMAND_MAP =
new ImmutableMap.Builder<String, Class<? extends Command>>()
.put("allocate_domain", AllocateDomainCommand.class)
.put("canonicalize_labels", CanonicalizeLabelsCommand.class)
.put("check_domain", CheckDomainCommand.class)
.put("check_domain_claims", CheckDomainClaimsCommand.class)
@ -56,19 +55,13 @@ public final class RegistryTool {
.put("delete_tld", DeleteTldCommand.class)
.put("deploy_invoicing_pipeline", DeployInvoicingPipelineCommand.class)
.put("deploy_spec11_pipeline", DeploySpec11PipelineCommand.class)
.put("domain_application_info", DomainApplicationInfoCommand.class)
.put("encrypt_escrow_deposit", EncryptEscrowDepositCommand.class)
.put("execute_epp", ExecuteEppCommand.class)
.put("generate_allocation_tokens", GenerateAllocationTokensCommand.class)
.put("generate_applications_report", GenerateApplicationsReportCommand.class)
.put("generate_auction_data", GenerateAuctionDataCommand.class)
.put("generate_dns_report", GenerateDnsReportCommand.class)
.put("generate_escrow_deposit", GenerateEscrowDepositCommand.class)
.put("generate_lordn", GenerateLordnCommand.class)
.put("generate_zone_files", GenerateZoneFilesCommand.class)
.put("get_application", GetApplicationCommand.class)
.put("get_application_ids", GetApplicationIdsCommand.class)
.put("get_applied_labels", GetAppliedLabelsCommand.class)
.put("get_claims_list", GetClaimsListCommand.class)
.put("get_contact", GetContactCommand.class)
.put("get_domain", GetDomainCommand.class)
@ -111,8 +104,6 @@ public final class RegistryTool {
.put("uniform_rapid_suspension", UniformRapidSuspensionCommand.class)
.put("unlock_domain", UnlockDomainCommand.class)
.put("unrenew_domain", UnrenewDomainCommand.class)
.put("update_application_status", UpdateApplicationStatusCommand.class)
.put("update_claims_notice", UpdateClaimsNoticeCommand.class)
.put("update_cursors", UpdateCursorsCommand.class)
.put("update_domain", UpdateDomainCommand.class)
.put("update_kms_keyring", UpdateKmsKeyringCommand.class)
@ -121,7 +112,6 @@ public final class RegistryTool {
.put("update_reserved_list", UpdateReservedListCommand.class)
.put("update_sandbox_tld", UpdateSandboxTldCommand.class)
.put("update_server_locks", UpdateServerLocksCommand.class)
.put("update_smd", UpdateSmdCommand.class)
.put("update_tld", UpdateTldCommand.class)
.put("upload_claims_list", UploadClaimsListCommand.class)
.put("validate_escrow_deposit", ValidateEscrowDepositCommand.class)

View file

@ -90,7 +90,6 @@ interface RegistryToolComponent {
void inject(DeploySpec11PipelineCommand command);
void inject(EncryptEscrowDepositCommand command);
void inject(GenerateAllocationTokensCommand command);
void inject(GenerateApplicationsReportCommand command);
void inject(GenerateDnsReportCommand command);
void inject(GenerateEscrowDepositCommand command);
void inject(GetKeyringSecretCommand command);

View file

@ -43,7 +43,7 @@ public final class ResaveEppResourceCommand extends MutatingCommand {
@Parameter(
names = "--id",
description = "Foreign key of the resource, or application ID of the domain application.")
description = "Foreign key of the resource.")
protected String uniqueId;
@Override

View file

@ -1,176 +0,0 @@
// Copyright 2017 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.tools;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static google.registry.model.EppResourceUtils.loadDomainApplication;
import static google.registry.model.domain.launch.ApplicationStatus.ALLOCATED;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.util.PreconditionsUtils.checkArgumentPresent;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.collect.ImmutableList;
import google.registry.model.domain.DomainApplication;
import google.registry.model.domain.launch.ApplicationStatus;
import google.registry.model.domain.launch.LaunchInfoResponseExtension;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppcommon.Trid;
import google.registry.model.poll.PendingActionNotificationResponse.DomainPendingActionNotificationResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.registrar.Registrar;
import google.registry.model.reporting.HistoryEntry;
import java.util.List;
import org.joda.time.DateTime;
/** Command to manually update the status of a domain application. */
@Parameters(separators = " =", commandDescription = "Manually update domain application status.")
final class UpdateApplicationStatusCommand extends MutatingCommand {
@Parameter(
names = "--ids",
description = "Comma-delimited list of application IDs to update the status.",
required = true)
private List<String> ids;
@Parameter(
names = "--msg",
description = "Message shown to registrars in the poll message.",
required = true)
private String message;
@Parameter(
names = "--status",
description = "The new application status.",
required = true)
private ApplicationStatus newStatus;
@Parameter(
names = "--history_client_id",
description = "Client id that made this change. Only recorded in the history entry.")
private String clientId = "CharlestonRoad";
@Override
protected void init() {
checkArgumentPresent(
Registrar.loadByClientId(clientId), "Registrar with client ID %s not found", clientId);
for (final String applicationId : ids) {
ofy().transact(() -> updateApplicationStatus(applicationId));
}
}
/**
* Stages changes to update the status of an application and also enqueue a poll message for the
* status change, which may contain a PendingActionNotificationResponse if this is a final status.
*
* <p>This method must be called from within a transaction.
*/
private void updateApplicationStatus(String applicationId) {
ofy().assertInTransaction();
DateTime now = ofy().getTransactionTime();
DomainApplication domainApplication =
loadDomainApplication(applicationId, now)
.orElseThrow(
() ->
new IllegalArgumentException(
"Domain application does not exist or is deleted"));
// It's not an error if the application already has the intended status. We want the method
// to be idempotent.
if (domainApplication.getApplicationStatus() == newStatus) {
System.err.printf("Domain application %s already has status %s\n", applicationId, newStatus);
return;
}
// Ensure domain does not already have a final status which it should not be updated from.
checkState(
!domainApplication.getApplicationStatus().isFinalStatus(),
"Domain application has final status %s",
domainApplication.getApplicationStatus());
// Update its status.
DomainApplication.Builder applicationBuilder = domainApplication.asBuilder()
.setApplicationStatus(newStatus)
.setLastEppUpdateTime(now)
// Use the current sponsor instead of the history client ID because the latter might be an
// internal client ID that we don't want to expose.
.setLastEppUpdateClientId(domainApplication.getCurrentSponsorClientId());
// Create a history entry (with no XML or Trid) to record that we are updating the status on
// this application.
HistoryEntry newHistoryEntry = new HistoryEntry.Builder()
.setType(HistoryEntry.Type.DOMAIN_APPLICATION_STATUS_UPDATE)
.setParent(domainApplication)
.setModificationTime(now)
.setClientId(clientId)
.setBySuperuser(true)
.build();
// Create a poll message informing the registrar that the application status was updated.
PollMessage.OneTime.Builder pollMessageBuilder = new PollMessage.OneTime.Builder()
.setClientId(domainApplication.getCurrentSponsorClientId())
.setEventTime(ofy().getTransactionTime())
.setMsg(message)
.setParent(newHistoryEntry)
.setResponseExtensions(ImmutableList.of(
new LaunchInfoResponseExtension.Builder()
.setApplicationId(domainApplication.getForeignKey())
.setPhase(domainApplication.getPhase())
.setApplicationStatus(newStatus)
.build()));
// If this is a final status (i.e. an end state), then we should remove pending create from the
// application and include a pending action notification in the poll message. Conversely, if
// this is not a final status, we should add pending create (which will already be there unless
// we're resurrecting an application).
if (newStatus.isFinalStatus()) {
applicationBuilder.removeStatusValue(StatusValue.PENDING_CREATE);
pollMessageBuilder.setResponseData(ImmutableList.of(
DomainPendingActionNotificationResponse.create(
domainApplication.getFullyQualifiedDomainName(),
ALLOCATED.equals(newStatus), // Whether the operation succeeded
getCreationTrid(domainApplication),
now)));
} else {
applicationBuilder.addStatusValue(StatusValue.PENDING_CREATE);
}
// Stage changes for all entities that need to be saved to Datastore.
stageEntityChange(domainApplication, applicationBuilder.build());
stageEntityChange(null, pollMessageBuilder.build());
stageEntityChange(null, newHistoryEntry);
}
/** Retrieve the transaction id of the operation which created this application. */
static Trid getCreationTrid(DomainApplication domainApplication) {
Trid creationTrid = domainApplication.getCreationTrid();
if (creationTrid == null) {
// If the creation TRID is not present on the application (this can happen for older
// applications written before this field was added), then we must read the earliest history
// entry for the application to retrieve it.
return checkNotNull(checkNotNull(ofy()
.load()
.type(HistoryEntry.class)
.ancestor(domainApplication)
.order("modificationTime")
.first()
.now()).getTrid());
}
return creationTrid;
}
}

View file

@ -1,119 +0,0 @@
// Copyright 2017 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.tools;
import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.model.EppResourceUtils.loadDomainApplication;
import static google.registry.model.ofy.ObjectifyService.ofy;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.net.InternetDomainName;
import google.registry.model.domain.DomainApplication;
import google.registry.model.domain.launch.LaunchNotice;
import google.registry.model.domain.launch.LaunchNotice.InvalidChecksumException;
import google.registry.model.reporting.HistoryEntry;
import org.joda.time.DateTime;
/** Command to update the claims notice on a domain application. */
@Parameters(separators = " =", commandDescription = "Update the claims notice on an application.")
final class UpdateClaimsNoticeCommand implements CommandWithRemoteApi {
@Parameter(
names = "--id",
description = "Application ID to update.",
required = true)
private String id;
@Parameter(
names = "--tcn_id",
description = "Trademark claims notice ID.",
required = true)
private String tcnId;
@Parameter(
names = "--validator_id",
description = "Trademark claims validator.")
private String validatorId = "tmch";
@Parameter(
names = "--expiration_time",
description = "Expiration time of claims notice.",
required = true)
private String expirationTime;
@Parameter(
names = "--accepted_time",
description = "Accepted time of claims notice.",
required = true)
private String acceptedTime;
@Override
public void run() {
final LaunchNotice launchNotice = LaunchNotice.create(
tcnId, validatorId, DateTime.parse(expirationTime), DateTime.parse(acceptedTime));
ofy()
.transact(
() -> {
try {
updateClaimsNotice(id, launchNotice);
} catch (InvalidChecksumException e) {
throw new RuntimeException(e);
}
});
}
private void updateClaimsNotice(String applicationId, LaunchNotice launchNotice)
throws InvalidChecksumException {
ofy().assertInTransaction();
DateTime now = ofy().getTransactionTime();
// Load the domain application.
DomainApplication domainApplication =
loadDomainApplication(applicationId, now)
.orElseThrow(
() ->
new IllegalArgumentException(
"Domain application does not exist or is deleted"));
// Make sure this isn't a sunrise application.
checkArgument(domainApplication.getEncodedSignedMarks().isEmpty(),
"Can't update claims notice on sunrise applications.");
// Validate the new launch notice checksum.
String domainLabel =
InternetDomainName.from(domainApplication.getFullyQualifiedDomainName()).parts().get(0);
launchNotice.validate(domainLabel);
DomainApplication updatedApplication = domainApplication.asBuilder()
.setLaunchNotice(launchNotice)
.setLastEppUpdateTime(now)
.setLastEppUpdateClientId(domainApplication.getCurrentSponsorClientId())
.build();
// Create a history entry (with no XML or Trid) to record that we are updating the application.
HistoryEntry newHistoryEntry = new HistoryEntry.Builder()
.setType(HistoryEntry.Type.DOMAIN_APPLICATION_UPDATE)
.setParent(domainApplication)
.setModificationTime(now)
.setClientId(domainApplication.getCurrentSponsorClientId())
.setBySuperuser(true)
.build();
// Save entities to Datastore.
ofy().save().<Object>entities(updatedApplication, newHistoryEntry);
}
}

View file

@ -1,124 +0,0 @@
// Copyright 2017 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.tools;
import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.model.EppResourceUtils.loadDomainApplication;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.tmch.TmchData.readEncodedSignedMark;
import static java.nio.charset.StandardCharsets.US_ASCII;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.collect.ImmutableList;
import com.google.common.net.InternetDomainName;
import google.registry.flows.EppException;
import google.registry.flows.domain.DomainFlowTmchUtils;
import google.registry.model.domain.DomainApplication;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.smd.EncodedSignedMark;
import google.registry.model.smd.SignedMark;
import google.registry.tools.params.PathParameter;
import java.nio.file.Files;
import java.nio.file.Path;
import javax.inject.Inject;
import org.joda.time.DateTime;
/** Command to update the SMD on a domain application. */
@Parameters(separators = " =", commandDescription = "Update the SMD on an application.")
final class UpdateSmdCommand implements CommandWithRemoteApi {
@Inject DomainFlowTmchUtils tmchUtils;
@Inject UpdateSmdCommand() {}
@Parameter(
names = "--id",
description = "Application ID to update.",
required = true)
private String id;
@Parameter(
names = "--smd",
description = "File containing the updated encoded SMD.",
validateWith = PathParameter.InputFile.class,
required = true)
private Path smdFile;
@Parameter(
names = "--reason",
description = "Special reason for the SMD update to record in the history entry.")
private String reason;
@Override
public void run() throws Exception {
final EncodedSignedMark encodedSignedMark =
readEncodedSignedMark(new String(Files.readAllBytes(smdFile), US_ASCII));
ofy()
.transact(
() -> {
try {
updateSmd(id, encodedSignedMark, reason);
} catch (EppException e) {
throw new RuntimeException(e);
}
});
}
private void updateSmd(
String applicationId, EncodedSignedMark encodedSignedMark, String reason)
throws EppException {
ofy().assertInTransaction();
DateTime now = ofy().getTransactionTime();
// Load the domain application.
DomainApplication domainApplication =
loadDomainApplication(applicationId, now)
.orElseThrow(
() ->
new IllegalArgumentException(
"Domain application does not exist or is deleted"));
// Make sure this is a sunrise application.
checkArgument(
!domainApplication.getEncodedSignedMarks().isEmpty(),
"Can't update SMD on a landrush application.");
// Verify the new SMD.
String domainLabel =
InternetDomainName.from(domainApplication.getFullyQualifiedDomainName()).parts().get(0);
SignedMark signedMark = tmchUtils.verifyEncodedSignedMark(encodedSignedMark, now);
tmchUtils.verifySignedMarkValidForDomainLabel(signedMark, domainLabel);
DomainApplication updatedApplication = domainApplication.asBuilder()
.setEncodedSignedMarks(ImmutableList.of(encodedSignedMark))
.setLastEppUpdateTime(now)
.setLastEppUpdateClientId(domainApplication.getCurrentSponsorClientId())
.build();
// Create a history entry (with no XML or Trid) to record that we are updating the application.
HistoryEntry newHistoryEntry = new HistoryEntry.Builder()
.setType(HistoryEntry.Type.DOMAIN_APPLICATION_UPDATE)
.setParent(domainApplication)
.setModificationTime(now)
.setClientId(domainApplication.getCurrentSponsorClientId())
.setBySuperuser(true)
.setReason("UpdateSmdCommand" + (reason != null ? ": " + reason : ""))
.build();
// Save entities to Datastore.
ofy().save().<Object>entities(updatedApplication, newHistoryEntry);
}
}

View file

@ -1,116 +0,0 @@
// Copyright 2019 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.tools.server;
import static google.registry.mapreduce.inputs.EppResourceInputs.createEntityInput;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.request.Action.Method.POST;
import static google.registry.util.PipelineUtils.createJobPath;
import com.google.appengine.tools.mapreduce.Mapper;
import com.google.common.collect.ImmutableList;
import com.google.common.flogger.FluentLogger;
import com.googlecode.objectify.Key;
import google.registry.mapreduce.MapreduceRunner;
import google.registry.model.domain.DomainApplication;
import google.registry.model.index.DomainApplicationIndex;
import google.registry.model.index.EppResourceIndex;
import google.registry.model.reporting.HistoryEntry;
import google.registry.request.Action;
import google.registry.request.Response;
import google.registry.request.auth.Auth;
import javax.inject.Inject;
/**
* Deletes all {@link DomainApplication} entities in Datastore.
*
* <p>This also deletes the corresponding {@link DomainApplicationIndex}, {@link EppResourceIndex},
* and descendent {@link HistoryEntry}s.
*/
@Action(path = "/_dr/task/killAllDomainApplications", method = POST, auth = Auth.AUTH_INTERNAL_ONLY)
public class KillAllDomainApplicationsAction implements Runnable {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@Inject MapreduceRunner mrRunner;
@Inject Response response;
@Inject
KillAllDomainApplicationsAction() {}
@Override
public void run() {
response.sendJavaScriptRedirect(
createJobPath(
mrRunner
.setJobName("Delete all domain applications and associated entities")
.setModuleName("tools")
.runMapOnly(
new KillAllDomainApplicationsMapper(),
ImmutableList.of(createEntityInput(DomainApplication.class)))));
}
static class KillAllDomainApplicationsMapper extends Mapper<DomainApplication, Void, Void> {
private static final long serialVersionUID = 2862967335000340688L;
@Override
public void map(final DomainApplication application) {
ofy()
.transact(
() -> {
if (ofy().load().entity(application).now() == null) {
getContext().incrementCounter("applications already deleted");
return;
}
Key<DomainApplication> applicationKey = Key.create(application);
DomainApplicationIndex dai =
ofy().load().key(DomainApplicationIndex.createKey(application)).now();
EppResourceIndex eri =
ofy().load().entity(EppResourceIndex.create(applicationKey)).now();
// This case is common and happens when the same domain name was applied for
// multiple times (i.e. there are multiple domain applications sharing a name). The
// first one that the mapreduce happens to process will delete the DAI and then
// subsequent ones will see the entity as already deleted, which is safe and
// expected.
if (dai == null) {
logger.atWarning().log(
"Missing domain application index for application %s.", applicationKey);
getContext().incrementCounter("missing domain application indexes");
} else {
ofy().delete().entity(dai);
}
// This case shouldn't be possible except in extremely rare circumstances, as this
// mapreduce itself is relying on EPP resource indexes to load the domain
// applications to delete.
if (eri == null) {
logger.atSevere().log(
"Missing EPP resource index for application %s.", applicationKey);
getContext().incrementCounter("missing EPP resource indexes");
} else {
ofy().delete().entity(eri);
}
// Delete the application, its descendents, and the indexes.
ofy().delete().keys(ofy().load().ancestor(application).keys());
logger.atInfo().log("Deleted domain application %s.", applicationKey);
getContext().incrementCounter("applications deleted");
});
}
}
}

View file

@ -26,8 +26,6 @@ import google.registry.config.RegistryEnvironment;
import google.registry.mapreduce.MapreduceRunner;
import google.registry.mapreduce.inputs.EppResourceInputs;
import google.registry.model.EppResource;
import google.registry.model.domain.DomainApplication;
import google.registry.model.index.DomainApplicationIndex;
import google.registry.model.index.EppResourceIndex;
import google.registry.model.index.ForeignKeyIndex;
import google.registry.request.Action;
@ -75,12 +73,11 @@ public class KillAllEppResourcesAction implements Runnable {
/**
* Delete an {@link EppResourceIndex}, its referent, all descendants of each referent, and the
* {@link ForeignKeyIndex} or {@link DomainApplicationIndex} of the referent, as appropriate.
* {@link ForeignKeyIndex} of the referent, as appropriate.
*
* <p>This will delete:
* <ul>
* <li>All {@link ForeignKeyIndex} types
* <li>{@link DomainApplicationIndex}
* <li>{@link EppResourceIndex}
* <li>All {@link EppResource} types
* <li>{@code HistoryEntry}
@ -98,9 +95,7 @@ public class KillAllEppResourcesAction implements Runnable {
}
EppResource resource = ofy().load().key(eri.getKey()).now();
// TODO(b/28247733): What about FKI's for renamed hosts?
Key<?> indexKey = resource instanceof DomainApplication
? DomainApplicationIndex.createKey((DomainApplication) resource)
: ForeignKeyIndex.createKey(resource);
Key<?> indexKey = ForeignKeyIndex.createKey(resource);
emitAndIncrementCounter(indexKey, indexKey);
}

View file

@ -1,89 +0,0 @@
// Copyright 2017 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.
{namespace domain.registry.tools}
/**
* Domain allocate request.
*/
{template .create stricthtml="false"}
{@param name: string}
{@param period: int}
{@param registrant: string}
{@param contacts: legacy_object_map<string, string>}
{@param authInfo: string}
{@param applicationRoid: string}
{@param applicationTime: string}
{@param? clTrid: string}
{@param? nameservers: list<string>}
{@param? smdId: string}
{@param? launchNotice: legacy_object_map<string, string>}
{@param? dsRecords: list<legacy_object_map<string, any>>}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<domain:create xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>{$name}</domain:name>
<domain:period unit="y">{$period}</domain:period>
{if isNonnull($nameservers) and length($nameservers) > 0}
<domain:ns>
{for $nameserver in $nameservers}
<domain:hostObj>{$nameserver}</domain:hostObj>
{/for}
</domain:ns>
{/if}
<domain:registrant>{$registrant}</domain:registrant>
{for $type in keys($contacts)}
<domain:contact type="{$type}">{$contacts[$type]}</domain:contact>
{/for}
<domain:authInfo>
<domain:pw>{$authInfo}</domain:pw>
</domain:authInfo>
</domain:create>
</create>
<extension>
<allocate:create xmlns:allocate="urn:google:params:xml:ns:allocate-1.0">
<allocate:applicationRoid>{$applicationRoid}</allocate:applicationRoid>
<allocate:applicationTime>{$applicationTime}</allocate:applicationTime>
{if isNonnull($smdId)}
<allocate:smdId>{$smdId}</allocate:smdId>
{/if}
{if isNonnull($launchNotice)}
<allocate:notice xmlns:launch="urn:ietf:params:xml:ns:launch-1.0">
<launch:noticeID>{$launchNotice['noticeId']}</launch:noticeID>
<launch:notAfter>{$launchNotice['expirationTime']}</launch:notAfter>
<launch:acceptedDate>{$launchNotice['acceptedTime']}</launch:acceptedDate>
</allocate:notice>
{/if}
</allocate:create>
{if isNonnull($dsRecords) and length($dsRecords) > 0}
<secDNS:create xmlns:secDNS="urn:ietf:params:xml:ns:secDNS-1.1">
{for $dsRecord in $dsRecords}
<secDNS:dsData>
<secDNS:keyTag>{$dsRecord['keyTag']}</secDNS:keyTag>
<secDNS:alg>{$dsRecord['algorithm']}</secDNS:alg>
<secDNS:digestType>{$dsRecord['digestType']}</secDNS:digestType>
<secDNS:digest>{$dsRecord['digest']}</secDNS:digest>
</secDNS:dsData>
{/for}
</secDNS:create>
{/if}
</extension>
{if isNonnull($clTrid)}
<clTRID>{$clTrid}</clTRID>
{/if}
</command>
</epp>
{/template}

View file

@ -1,43 +0,0 @@
// Copyright 2017 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.
{namespace domain.registry.tools}
/**
* Domain application info request
*/
{template .domainapplicationinfo stricthtml="false"}
{@param domainName: string}
{@param id: string}
{@param phase: string}
{@param? subphase: string}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<info>
<domain:info
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>{$domainName}</domain:name>
</domain:info>
</info>
<extension>
<launch:info
xmlns:launch="urn:ietf:params:xml:ns:launch-1.0">
<launch:phase {if $subphase}name="{$subphase}"{/if}>{$phase}</launch:phase>
<launch:applicationID>{$id}</launch:applicationID>
</launch:info>
</extension>
<clTRID>RegistryTool</clTRID>
</command>
</epp>
{/template}