mirror of
https://github.com/google/nomulus.git
synced 2025-05-14 16:37:13 +02:00
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:
parent
c74ffd7559
commit
580302898d
282 changed files with 344 additions and 17634 deletions
229
docs/flows.md
229
docs/flows.md
|
@ -225,227 +225,6 @@ An EPP flow that updates a contact.
|
|||
* Cannot add and remove the same value.
|
||||
* Declining contact disclosure is disallowed by server policy.
|
||||
|
||||
## DomainAllocateFlow
|
||||
|
||||
### Description
|
||||
|
||||
An EPP flow that allocates a new domain resource from a domain application.
|
||||
|
||||
Note that this flow is only run by superusers.
|
||||
|
||||
|
||||
### Errors
|
||||
|
||||
* 2004
|
||||
* New registration period exceeds maximum number of years.
|
||||
* 2201
|
||||
* Only a superuser can allocate domains.
|
||||
* 2302
|
||||
* Resource with this id already exists.
|
||||
* 2303
|
||||
* Domain application with specific ROID does not exist.
|
||||
* 2304
|
||||
* Domain application already has a final status.
|
||||
* Registrant is not whitelisted for this TLD.
|
||||
* Nameservers are not whitelisted for this domain.
|
||||
* Nameservers are not whitelisted for this TLD.
|
||||
* Nameservers not specified for domain with nameserver-restricted
|
||||
reservation.
|
||||
* Nameservers not specified for domain on TLD with nameserver whitelist.
|
||||
|
||||
## DomainApplicationCreateFlow
|
||||
|
||||
### Description
|
||||
|
||||
An EPP flow that creates a new application for a domain resource.
|
||||
|
||||
|
||||
### Errors
|
||||
|
||||
* 2002
|
||||
* A notice cannot be specified when using a signed mark.
|
||||
* Sunrise applications are disallowed during landrush.
|
||||
* Command is not allowed in the current registry phase.
|
||||
* 2003
|
||||
* Landrush applications are disallowed during sunrise.
|
||||
* Fees must be explicitly acknowledged when performing any operations on a
|
||||
premium name.
|
||||
* The provided mark does not match the desired domain label.
|
||||
* 2004
|
||||
* The acceptance time specified in the claim notice is more than 48 hours
|
||||
in the past.
|
||||
* New registration period exceeds maximum number of years.
|
||||
* The expiration time specified in the claim notice has elapsed.
|
||||
* The fees passed in the transform command do not match the fees that will
|
||||
be charged.
|
||||
* Domain label is not allowed by IDN table.
|
||||
* The checksum in the specified TCNID does not validate.
|
||||
* Domain name is under tld which doesn't exist.
|
||||
* 2005
|
||||
* Domain name must have exactly one part above the TLD.
|
||||
* Domain name must not equal an existing multi-part TLD.
|
||||
* The requested fee is expressed in a scale that is invalid for the given
|
||||
currency.
|
||||
* The specified TCNID is invalid.
|
||||
* Signed mark data is improperly encoded.
|
||||
* Error while parsing encoded signed mark data.
|
||||
* 2102
|
||||
* The 'maxSigLife' setting is not supported.
|
||||
* The 'grace-period', 'applied' and 'refundable' fields are disallowed by
|
||||
server policy.
|
||||
* 2103
|
||||
* Specified extension is not implemented.
|
||||
* 2201
|
||||
* Registrar is not authorized to access this TLD.
|
||||
* Registrar must be active in order to perform this operation.
|
||||
* 2302
|
||||
* Resource with this id already exists.
|
||||
* This name has already been claimed by a sunrise applicant.
|
||||
* 2303
|
||||
* Resource linked to this domain does not exist.
|
||||
* 2304
|
||||
* The claims period for this TLD has ended.
|
||||
* Requested domain is reserved.
|
||||
* Requested domain requires a claims notice.
|
||||
* Nameservers are not whitelisted for this domain.
|
||||
* Nameservers are not whitelisted for this TLD.
|
||||
* Nameservers not specified for domain with nameserver-restricted
|
||||
reservation.
|
||||
* Nameservers not specified for domain on TLD with nameserver whitelist.
|
||||
* The requested domain name is on the premium price list, and this
|
||||
registrar has blocked premium registrations.
|
||||
* Registrant is not whitelisted for this TLD.
|
||||
* Requested domain does not require a claims notice.
|
||||
* 2306
|
||||
* Domain names can only contain a-z, 0-9, '.' and '-'.
|
||||
* Periods for domain registrations must be specified in years.
|
||||
* Encoded signed marks must use base64 encoding.
|
||||
* The requested fees cannot be provided in the requested currency.
|
||||
* Non-IDN domain names cannot contain hyphens in the third or fourth
|
||||
position.
|
||||
* Domain labels cannot be longer than 63 characters.
|
||||
* More than one contact for a given role is not allowed.
|
||||
* No part of a domain name can be empty.
|
||||
* Domain name starts with xn-- but is not a valid IDN.
|
||||
* The specified trademark validator is not supported.
|
||||
* Declared launch extension phase does not match the current registry
|
||||
phase.
|
||||
* Domain labels cannot begin with a dash.
|
||||
* Missing type attribute for contact.
|
||||
* The provided mark is not yet valid.
|
||||
* The provided mark has expired.
|
||||
* Signed marks must be encoded.
|
||||
* Certificate used in signed mark signature has expired.
|
||||
* Certificate parsing error, or possibly a bad provider or algorithm.
|
||||
* Certificate used in signed mark signature has expired.
|
||||
* Certificate used in signed mark signature was revoked by ICANN.
|
||||
* Invalid signature on a signed mark.
|
||||
* Signed mark data is revoked.
|
||||
* Invalid signature on a signed mark.
|
||||
* Too many DS records set on a domain.
|
||||
* Too many nameservers set on this domain.
|
||||
* Only one signed mark is allowed per application.
|
||||
* Domain labels cannot end with a dash.
|
||||
* Only encoded signed marks are supported.
|
||||
|
||||
## DomainApplicationDeleteFlow
|
||||
|
||||
### Description
|
||||
|
||||
An EPP flow that deletes a domain application.
|
||||
|
||||
|
||||
### Errors
|
||||
|
||||
* 2002
|
||||
* Command is not allowed in the current registry phase.
|
||||
* 2103
|
||||
* Specified extension is not implemented.
|
||||
* 2201
|
||||
* The specified resource belongs to another client.
|
||||
* Registrar is not authorized to access this TLD.
|
||||
* 2303
|
||||
* Resource with this id does not exist.
|
||||
* 2304
|
||||
* A sunrise application cannot be deleted during landrush.
|
||||
* 2306
|
||||
* Application referenced does not match specified domain name.
|
||||
* Declared launch extension phase does not match the current registry
|
||||
phase.
|
||||
|
||||
## DomainApplicationInfoFlow
|
||||
|
||||
### Description
|
||||
|
||||
An EPP flow that returns information about a domain application.
|
||||
|
||||
Only the registrar that owns the application can see its info. The flow can
|
||||
optionally include delegated hosts in its response.
|
||||
|
||||
|
||||
### Errors
|
||||
|
||||
* 2003
|
||||
* Application id is required.
|
||||
* 2201
|
||||
* The specified resource belongs to another client.
|
||||
* 2303
|
||||
* Resource with this id does not exist.
|
||||
* 2306
|
||||
* Application referenced does not match specified domain name.
|
||||
* Declared launch extension phase does not match phase of the application.
|
||||
|
||||
## DomainApplicationUpdateFlow
|
||||
|
||||
### Description
|
||||
|
||||
An EPP flow that updates a domain application.
|
||||
|
||||
Updates can change contacts, nameservers and delegation signer data of an
|
||||
application. Updates cannot change the domain name that is being applied for.
|
||||
|
||||
|
||||
### Errors
|
||||
|
||||
* 2003
|
||||
* At least one of 'add' or 'rem' is required on a secDNS update.
|
||||
* Admin contact is required.
|
||||
* Technical contact is required.
|
||||
* 2004
|
||||
* The specified status value cannot be set by clients.
|
||||
* The fees passed in the transform command do not match the fees that will
|
||||
be charged.
|
||||
* 2102
|
||||
* Changing 'maxSigLife' is not supported.
|
||||
* The 'urgent' attribute is not supported.
|
||||
* 2103
|
||||
* Specified extension is not implemented.
|
||||
* 2201
|
||||
* The specified resource belongs to another client.
|
||||
* Registrar is not authorized to access this TLD.
|
||||
* 2303
|
||||
* Resource with this id does not exist.
|
||||
* Resource linked to this domain does not exist.
|
||||
* 2304
|
||||
* This resource has clientUpdateProhibited on it, and the update does not
|
||||
clear that status.
|
||||
* Resource status prohibits this operation.
|
||||
* Nameservers are not whitelisted for this TLD.
|
||||
* Nameservers not specified for domain on TLD with nameserver whitelist.
|
||||
* Nameservers are not whitelisted for this domain.
|
||||
* Nameservers not specified for domain with nameserver-restricted
|
||||
reservation.
|
||||
* Registrant is not whitelisted for this TLD.
|
||||
* Application status prohibits this domain update.
|
||||
* 2306
|
||||
* Cannot add and remove the same value.
|
||||
* Application referenced does not match specified domain name.
|
||||
* More than one contact for a given role is not allowed.
|
||||
* Missing type attribute for contact.
|
||||
* The secDNS:all element must have value 'true' if present.
|
||||
* Too many DS records set on a domain.
|
||||
* Too many nameservers set on this domain.
|
||||
|
||||
## DomainCheckFlow
|
||||
|
||||
### Description
|
||||
|
@ -498,7 +277,6 @@ An EPP flow that checks whether domain labels are trademarked.
|
|||
|
||||
* 2002
|
||||
* Command is not allowed in the current registry phase.
|
||||
* Claims checks are not allowed during sunrise.
|
||||
* Claims checks are not allowed with allocation tokens.
|
||||
* 2004
|
||||
* Domain name is under tld which doesn't exist.
|
||||
|
@ -564,7 +342,6 @@ An EPP flow that creates a new domain resource.
|
|||
* 2303
|
||||
* Resource linked to this domain does not exist.
|
||||
* 2304
|
||||
* There is an open application for this domain.
|
||||
* The claims period for this TLD has ended.
|
||||
* Requested domain does not have nameserver-restricted reservation for a
|
||||
TLD that requires such a reservation to create domains.
|
||||
|
@ -945,12 +722,6 @@ applied by the superuser. As such, adding or removing these statuses incurs a
|
|||
billing event. There will be only one charge per update, even if several such
|
||||
statuses are updated at once.
|
||||
|
||||
If a domain was created during the sunrise or landrush phases of a TLD, is still
|
||||
within the sunrushAddGracePeriod and has not yet been delegated in DNS, then it
|
||||
will not yet have been billed for. Any update that causes the name to be
|
||||
delegated (such * as adding nameservers or removing a hold status) will cause
|
||||
the domain to convert to a normal create and be billed for accordingly.
|
||||
|
||||
|
||||
### Errors
|
||||
|
||||
|
|
|
@ -15,9 +15,6 @@ def outcastTestPatterns = [
|
|||
"google/registry/batch/RefreshDnsOnHostRenameActionTest.*",
|
||||
"google/registry/flows/CheckApiActionTest.*",
|
||||
"google/registry/flows/EppLifecycleHostTest.*",
|
||||
"google/registry/flows/domain/DomainAllocateFlowTest.*",
|
||||
"google/registry/flows/domain/DomainApplicationCreateFlowTest.*",
|
||||
"google/registry/flows/domain/DomainApplicationUpdateFlowTest.*",
|
||||
"google/registry/flows/domain/DomainCreateFlowTest.*",
|
||||
"google/registry/flows/domain/DomainUpdateFlowTest.*",
|
||||
"google/registry/tools/CreateDomainCommandTest.*",
|
||||
|
|
|
@ -106,13 +106,9 @@ import org.joda.time.Duration;
|
|||
|
||||
/**
|
||||
* A mapreduce that processes batch asynchronous deletions of contact and host resources by mapping
|
||||
* over all domains and domain applications and checking for any references to the contacts/hosts in
|
||||
* pending deletion.
|
||||
* over all domains and checking for any references to the contacts/hosts in pending deletion.
|
||||
*/
|
||||
@Action(
|
||||
path = "/_dr/task/deleteContactsAndHosts",
|
||||
auth = Auth.AUTH_INTERNAL_ONLY
|
||||
)
|
||||
@Action(path = "/_dr/task/deleteContactsAndHosts", auth = Auth.AUTH_INTERNAL_ONLY)
|
||||
public class DeleteContactsAndHostsAction implements Runnable {
|
||||
|
||||
static final String KIND_CONTACT = getKind(ContactResource.class);
|
||||
|
|
|
@ -41,7 +41,6 @@ import google.registry.dns.DnsQueue;
|
|||
import google.registry.mapreduce.MapreduceRunner;
|
||||
import google.registry.mapreduce.inputs.EppResourceInputs;
|
||||
import google.registry.model.EppResourceUtils;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.domain.DomainResource;
|
||||
import google.registry.model.index.EppResourceIndex;
|
||||
|
@ -167,23 +166,17 @@ public class DeleteProberDataAction implements Runnable {
|
|||
}
|
||||
|
||||
private void deleteDomain(final Key<DomainBase> domainKey) {
|
||||
final DomainBase domainBase = ofy().load().key(domainKey).now();
|
||||
final DomainResource domain = (DomainResource) ofy().load().key(domainKey).now();
|
||||
|
||||
DateTime now = DateTime.now(UTC);
|
||||
|
||||
if (domainBase == null) {
|
||||
if (domain == null) {
|
||||
// Depending on how stale Datastore indexes are, we can get keys to resources that are
|
||||
// already deleted (e.g. by a recent previous invocation of this mapreduce). So ignore them.
|
||||
getContext().incrementCounter("already deleted");
|
||||
return;
|
||||
}
|
||||
if (domainBase instanceof DomainApplication) {
|
||||
// Cover the case where we somehow have a domain application with a prober ROID suffix.
|
||||
getContext().incrementCounter("skipped, domain application");
|
||||
return;
|
||||
}
|
||||
|
||||
DomainResource domain = (DomainResource) domainBase;
|
||||
String domainName = domain.getFullyQualifiedDomainName();
|
||||
if (domainName.equals("nic." + domain.getTld())) {
|
||||
getContext().incrementCounter("skipped, NIC domain");
|
||||
|
|
|
@ -72,12 +72,6 @@
|
|||
<url-pattern>/_dr/task/resaveAllHistoryEntries</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Mapreduce to delete all domain applications. -->
|
||||
<servlet-mapping>
|
||||
<servlet-name>tools-servlet</servlet-name>
|
||||
<url-pattern>/_dr/task/killAllDomainApplications</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Mapreduce to delete EppResources, children, and indices. -->
|
||||
<servlet-mapping>
|
||||
<servlet-name>tools-servlet</servlet-name>
|
||||
|
|
|
@ -250,12 +250,4 @@ public abstract class EppException extends Exception {
|
|||
super("Specified protocol version is not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
/** Command failed. */
|
||||
@EppResultCode(Code.COMMAND_FAILED)
|
||||
public static class CommandFailedException extends EppException {
|
||||
public CommandFailedException() {
|
||||
super("Command failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,11 +30,6 @@ import google.registry.flows.contact.ContactTransferRejectFlow;
|
|||
import google.registry.flows.contact.ContactTransferRequestFlow;
|
||||
import google.registry.flows.contact.ContactUpdateFlow;
|
||||
import google.registry.flows.custom.CustomLogicModule;
|
||||
import google.registry.flows.domain.DomainAllocateFlow;
|
||||
import google.registry.flows.domain.DomainApplicationCreateFlow;
|
||||
import google.registry.flows.domain.DomainApplicationDeleteFlow;
|
||||
import google.registry.flows.domain.DomainApplicationInfoFlow;
|
||||
import google.registry.flows.domain.DomainApplicationUpdateFlow;
|
||||
import google.registry.flows.domain.DomainCheckFlow;
|
||||
import google.registry.flows.domain.DomainClaimsCheckFlow;
|
||||
import google.registry.flows.domain.DomainCreateFlow;
|
||||
|
@ -86,11 +81,6 @@ public interface FlowComponent {
|
|||
ContactTransferRejectFlow contactTransferRejectFlow();
|
||||
ContactTransferRequestFlow contactTransferRequestFlow();
|
||||
ContactUpdateFlow contactUpdateFlow();
|
||||
DomainAllocateFlow domainAllocateFlow();
|
||||
DomainApplicationCreateFlow domainApplicationCreateFlow();
|
||||
DomainApplicationDeleteFlow domainApplicationDeleteFlow();
|
||||
DomainApplicationInfoFlow domainApplicationInfoFlow();
|
||||
DomainApplicationUpdateFlow domainApplicationUpdateFlow();
|
||||
DomainCheckFlow domainCheckFlow();
|
||||
DomainClaimsCheckFlow domainClaimsCheckFlow();
|
||||
DomainCreateFlow domainCreateFlow();
|
||||
|
@ -140,11 +130,6 @@ public interface FlowComponent {
|
|||
: clazz.equals(ContactTransferRejectFlow.class) ? flows.contactTransferRejectFlow()
|
||||
: clazz.equals(ContactTransferRequestFlow.class) ? flows.contactTransferRequestFlow()
|
||||
: clazz.equals(ContactUpdateFlow.class) ? flows.contactUpdateFlow()
|
||||
: clazz.equals(DomainAllocateFlow.class) ? flows.domainAllocateFlow()
|
||||
: clazz.equals(DomainApplicationCreateFlow.class) ? flows.domainApplicationCreateFlow()
|
||||
: clazz.equals(DomainApplicationDeleteFlow.class) ? flows.domainApplicationDeleteFlow()
|
||||
: clazz.equals(DomainApplicationInfoFlow.class) ? flows.domainApplicationInfoFlow()
|
||||
: clazz.equals(DomainApplicationUpdateFlow.class) ? flows.domainApplicationUpdateFlow()
|
||||
: clazz.equals(DomainCheckFlow.class) ? flows.domainCheckFlow()
|
||||
: clazz.equals(DomainClaimsCheckFlow.class) ? flows.domainClaimsCheckFlow()
|
||||
: clazz.equals(DomainCreateFlow.class) ? flows.domainCreateFlow()
|
||||
|
|
|
@ -15,13 +15,11 @@
|
|||
package google.registry.flows;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.base.Strings.nullToEmpty;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import google.registry.flows.picker.FlowPicker;
|
||||
import google.registry.model.domain.launch.ApplicationIdTargetExtension;
|
||||
import google.registry.model.domain.metadata.MetadataExtension;
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.model.eppcommon.Trid;
|
||||
|
@ -205,19 +203,6 @@ public class FlowModule {
|
|||
return ((SingleResourceCommand) resourceCommand).getTargetId();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FlowScope
|
||||
@ApplicationId
|
||||
static String provideApplicationId(EppInput eppInput) {
|
||||
// Treat a missing application id as empty so we can always inject a non-null value.
|
||||
Optional<ApplicationIdTargetExtension> extension =
|
||||
eppInput.getSingleExtension(ApplicationIdTargetExtension.class);
|
||||
checkState(
|
||||
extension.isPresent(),
|
||||
"ApplicationIdTargetExtension must be used to provide the application ID");
|
||||
return nullToEmpty(extension.get().getApplicationId());
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FlowScope
|
||||
@PollMessageId
|
||||
|
@ -294,11 +279,6 @@ public class FlowModule {
|
|||
@Documented
|
||||
public @interface TargetId {}
|
||||
|
||||
/** Dagger qualifier for the application id for domain application flows. */
|
||||
@Qualifier
|
||||
@Documented
|
||||
public @interface ApplicationId {}
|
||||
|
||||
/** Dagger qualifier for the message id for poll flows. */
|
||||
@Qualifier
|
||||
@Documented
|
||||
|
|
|
@ -32,11 +32,6 @@ import google.registry.model.eppinput.EppInput;
|
|||
*/
|
||||
public class CustomLogicFactory {
|
||||
|
||||
public DomainApplicationCreateFlowCustomLogic forDomainApplicationCreateFlow(
|
||||
EppInput eppInput, SessionMetadata sessionMetadata, FlowMetadata flowMetadata) {
|
||||
return new DomainApplicationCreateFlowCustomLogic(eppInput, sessionMetadata, flowMetadata);
|
||||
}
|
||||
|
||||
public DomainCreateFlowCustomLogic forDomainCreateFlow(
|
||||
EppInput eppInput, SessionMetadata sessionMetadata, FlowMetadata flowMetadata) {
|
||||
return new DomainCreateFlowCustomLogic(eppInput, sessionMetadata, flowMetadata);
|
||||
|
|
|
@ -24,15 +24,6 @@ import google.registry.model.eppinput.EppInput;
|
|||
@Module
|
||||
public class CustomLogicModule {
|
||||
|
||||
@Provides
|
||||
static DomainApplicationCreateFlowCustomLogic provideDomainApplicationCreateFlowCustomLogic(
|
||||
CustomLogicFactory factory,
|
||||
EppInput eppInput,
|
||||
SessionMetadata sessionMetadata,
|
||||
FlowMetadata flowMetadata) {
|
||||
return factory.forDomainApplicationCreateFlow(eppInput, sessionMetadata, flowMetadata);
|
||||
}
|
||||
|
||||
@Provides
|
||||
static DomainCreateFlowCustomLogic provideDomainCreateFlowCustomLogic(
|
||||
CustomLogicFactory factory,
|
||||
|
|
|
@ -1,221 +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.flows.custom;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.net.InternetDomainName;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.FlowMetadata;
|
||||
import google.registry.flows.SessionMetadata;
|
||||
import google.registry.flows.domain.DomainApplicationCreateFlow;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.eppoutput.EppResponse.ResponseData;
|
||||
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
|
||||
/**
|
||||
* A no-op base class for {@link DomainApplicationCreateFlow} custom logic.
|
||||
*
|
||||
* <p>Extend this class and override the hook(s) to perform custom logic.
|
||||
*/
|
||||
public class DomainApplicationCreateFlowCustomLogic extends BaseFlowCustomLogic {
|
||||
|
||||
protected DomainApplicationCreateFlowCustomLogic(
|
||||
EppInput eppInput, SessionMetadata sessionMetadata, FlowMetadata flowMetadata) {
|
||||
super(eppInput, sessionMetadata, flowMetadata);
|
||||
}
|
||||
|
||||
/** A hook that runs before any validation. This is useful to e.g. add allowable extensions. */
|
||||
@SuppressWarnings("unused")
|
||||
public void beforeValidation() throws EppException {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/** A hook that runs at the end of the validation step to perform additional validation. */
|
||||
@SuppressWarnings("unused")
|
||||
public void afterValidation(AfterValidationParameters parameters) throws EppException {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* A hook that runs before new entities are persisted, allowing them to be changed.
|
||||
*
|
||||
* <p>It returns the actual entity changes that should be persisted to Datastore. It is important
|
||||
* to be careful when changing the flow behavior for existing entities, because the core logic
|
||||
* across many different flows expects the existence of these entities and many of the fields on
|
||||
* them.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public EntityChanges beforeSave(BeforeSaveParameters parameters) throws EppException {
|
||||
return parameters.entityChanges();
|
||||
}
|
||||
|
||||
/**
|
||||
* A hook that runs before the response is returned.
|
||||
*
|
||||
* <p>This takes the {@link ResponseData} and {@link ResponseExtension}s as input and returns
|
||||
* them, potentially with modifications.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public BeforeResponseReturnData beforeResponse(BeforeResponseParameters parameters)
|
||||
throws EppException {
|
||||
return BeforeResponseReturnData.newBuilder()
|
||||
.setResData(parameters.resData())
|
||||
.setResponseExtensions(parameters.responseExtensions())
|
||||
.build();
|
||||
}
|
||||
|
||||
/** A class to encapsulate parameters for a call to {@link #afterValidation}. */
|
||||
@AutoValue
|
||||
public abstract static class AfterValidationParameters extends ImmutableObject {
|
||||
|
||||
/** The parsed domain name of the domain that is being applied for. */
|
||||
public abstract InternetDomainName domainName();
|
||||
|
||||
/**
|
||||
* The number of years that the application is requesting registration for.
|
||||
*
|
||||
* <p>On standard TLDs, this is usually 1.
|
||||
*/
|
||||
public abstract int years();
|
||||
|
||||
public static Builder newBuilder() {
|
||||
return new AutoValue_DomainApplicationCreateFlowCustomLogic_AfterValidationParameters
|
||||
.Builder();
|
||||
}
|
||||
|
||||
/** Builder for {@link AfterValidationParameters}. */
|
||||
@AutoValue.Builder
|
||||
public abstract static class Builder {
|
||||
|
||||
public abstract Builder setDomainName(InternetDomainName domainName);
|
||||
|
||||
public abstract Builder setYears(int years);
|
||||
|
||||
public abstract AfterValidationParameters build();
|
||||
}
|
||||
}
|
||||
|
||||
/** A class to encapsulate parameters for a call to {@link #beforeSave}. */
|
||||
@AutoValue
|
||||
public abstract static class BeforeSaveParameters extends ImmutableObject {
|
||||
|
||||
/**
|
||||
* The new {@link DomainApplication} entity that is going to be persisted at the end of the
|
||||
* transaction.
|
||||
*/
|
||||
public abstract DomainApplication newApplication();
|
||||
|
||||
/**
|
||||
* The new {@link HistoryEntry} entity for the application's creation that is going to be
|
||||
* persisted at the end of the transaction.
|
||||
*/
|
||||
public abstract HistoryEntry historyEntry();
|
||||
|
||||
/**
|
||||
* The collection of {@link EntityChanges} (including new entities and those to delete) that
|
||||
* will be persisted at the end of the transaction.
|
||||
*
|
||||
* <p>Note that the new application and history entry are also included as saves in this
|
||||
* collection, and are separated out above solely for convenience, as they are most likely to
|
||||
* need to be changed. Removing them from the collection will cause them not to be saved, which
|
||||
* is most likely not what you intended.
|
||||
*/
|
||||
public abstract EntityChanges entityChanges();
|
||||
|
||||
/**
|
||||
* The number of years that the application is requesting registration for.
|
||||
*
|
||||
* <p>On standard TLDs, this is usually 1.
|
||||
*/
|
||||
public abstract int years();
|
||||
|
||||
public static Builder newBuilder() {
|
||||
return new AutoValue_DomainApplicationCreateFlowCustomLogic_BeforeSaveParameters.Builder();
|
||||
}
|
||||
|
||||
/** Builder for {@link BeforeSaveParameters}. */
|
||||
@AutoValue.Builder
|
||||
public abstract static class Builder {
|
||||
|
||||
public abstract Builder setNewApplication(DomainApplication newApplication);
|
||||
|
||||
public abstract Builder setHistoryEntry(HistoryEntry historyEntry);
|
||||
|
||||
public abstract Builder setEntityChanges(EntityChanges entityChanges);
|
||||
|
||||
public abstract Builder setYears(int years);
|
||||
|
||||
public abstract BeforeSaveParameters build();
|
||||
}
|
||||
}
|
||||
|
||||
/** A class to encapsulate parameters for a call to {@link #beforeResponse}. */
|
||||
@AutoValue
|
||||
public abstract static class BeforeResponseParameters extends ImmutableObject {
|
||||
|
||||
public abstract ResponseData resData();
|
||||
|
||||
public abstract ImmutableList<? extends ResponseExtension> responseExtensions();
|
||||
|
||||
public static BeforeResponseParameters.Builder newBuilder() {
|
||||
return new AutoValue_DomainApplicationCreateFlowCustomLogic_BeforeResponseParameters
|
||||
.Builder();
|
||||
}
|
||||
|
||||
/** Builder for {@link DomainApplicationCreateFlowCustomLogic.BeforeResponseParameters}. */
|
||||
@AutoValue.Builder
|
||||
public abstract static class Builder {
|
||||
|
||||
public abstract BeforeResponseParameters.Builder setResData(ResponseData resData);
|
||||
|
||||
public abstract BeforeResponseParameters.Builder setResponseExtensions(
|
||||
ImmutableList<? extends ResponseExtension> responseExtensions);
|
||||
|
||||
public abstract BeforeResponseParameters build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A class to encapsulate parameters for the return values from a call to {@link #beforeResponse}.
|
||||
*/
|
||||
@AutoValue
|
||||
public abstract static class BeforeResponseReturnData extends ImmutableObject {
|
||||
|
||||
public abstract ResponseData resData();
|
||||
|
||||
public abstract ImmutableList<? extends ResponseExtension> responseExtensions();
|
||||
|
||||
public static BeforeResponseReturnData.Builder newBuilder() {
|
||||
return new AutoValue_DomainApplicationCreateFlowCustomLogic_BeforeResponseReturnData
|
||||
.Builder();
|
||||
}
|
||||
|
||||
/** Builder for {@link DomainApplicationCreateFlowCustomLogic.BeforeResponseReturnData}. */
|
||||
@AutoValue.Builder
|
||||
public abstract static class Builder {
|
||||
|
||||
public abstract BeforeResponseReturnData.Builder setResData(ResponseData resData);
|
||||
|
||||
public abstract BeforeResponseReturnData.Builder setResponseExtensions(
|
||||
ImmutableList<? extends ResponseExtension> responseExtensions);
|
||||
|
||||
public abstract BeforeResponseReturnData build();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,7 +22,6 @@ import google.registry.flows.SessionMetadata;
|
|||
import google.registry.flows.domain.DomainPricingLogic;
|
||||
import google.registry.flows.domain.FeesAndCredits;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.registry.Registry;
|
||||
import org.joda.time.DateTime;
|
||||
|
@ -39,13 +38,6 @@ public class DomainPricingCustomLogic extends BaseFlowCustomLogic {
|
|||
super(eppInput, sessionMetadata, flowMetadata);
|
||||
}
|
||||
|
||||
/** A hook that customizes the application update price. */
|
||||
@SuppressWarnings("unused")
|
||||
public FeesAndCredits customizeApplicationUpdatePrice(
|
||||
ApplicationUpdatePriceParameters priceParameters) throws EppException {
|
||||
return priceParameters.feesAndCredits();
|
||||
}
|
||||
|
||||
/** A hook that customizes the create price. */
|
||||
@SuppressWarnings("unused")
|
||||
public FeesAndCredits customizeCreatePrice(CreatePriceParameters priceParameters)
|
||||
|
@ -81,38 +73,6 @@ public class DomainPricingCustomLogic extends BaseFlowCustomLogic {
|
|||
return priceParameters.feesAndCredits();
|
||||
}
|
||||
|
||||
/** A class to encapsulate parameters for a call to {@link #customizeApplicationUpdatePrice} . */
|
||||
@AutoValue
|
||||
public abstract static class ApplicationUpdatePriceParameters extends ImmutableObject {
|
||||
|
||||
public abstract FeesAndCredits feesAndCredits();
|
||||
|
||||
public abstract Registry registry();
|
||||
|
||||
public abstract DomainApplication domainApplication();
|
||||
|
||||
public abstract DateTime asOfDate();
|
||||
|
||||
public static Builder newBuilder() {
|
||||
return new AutoValue_DomainPricingCustomLogic_ApplicationUpdatePriceParameters.Builder();
|
||||
}
|
||||
|
||||
/** Builder for {@link ApplicationUpdatePriceParameters}. */
|
||||
@AutoValue.Builder
|
||||
public abstract static class Builder {
|
||||
|
||||
public abstract Builder setFeesAndCredits(FeesAndCredits feesAndCredits);
|
||||
|
||||
public abstract Builder setRegistry(Registry registry);
|
||||
|
||||
public abstract Builder setDomainApplication(DomainApplication domainApplication);
|
||||
|
||||
public abstract Builder setAsOfDate(DateTime asOfDate);
|
||||
|
||||
public abstract ApplicationUpdatePriceParameters build();
|
||||
}
|
||||
}
|
||||
|
||||
/** A class to encapsulate parameters for a call to {@link #customizeCreatePrice} . */
|
||||
@AutoValue
|
||||
public abstract static class CreatePriceParameters extends ImmutableObject {
|
||||
|
|
|
@ -1,424 +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.flows.domain;
|
||||
|
||||
import static com.google.common.collect.MoreCollectors.onlyElement;
|
||||
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyResourceDoesNotExist;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.COLLISION_MESSAGE;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.cloneAndLinkReferences;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.createFeeCreateResponse;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.getReservationTypes;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateCreateCommandContactsAndNameservers;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateDomainName;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateDomainNameWithIdnTables;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateRegistrationPeriod;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateSecDnsExtension;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyUnitIsYears;
|
||||
import static google.registry.model.EppResourceUtils.createDomainRepoId;
|
||||
import static google.registry.model.EppResourceUtils.loadDomainApplication;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.pricing.PricingEngineProxy.getDomainCreateCost;
|
||||
import static google.registry.util.CollectionUtils.isNullOrEmpty;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.leapSafeAddYears;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.common.net.InternetDomainName;
|
||||
import com.googlecode.objectify.Key;
|
||||
import dagger.Lazy;
|
||||
import google.registry.dns.DnsQueue;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppException.AuthorizationErrorException;
|
||||
import google.registry.flows.EppException.ObjectDoesNotExistException;
|
||||
import google.registry.flows.EppException.StatusProhibitsOperationException;
|
||||
import google.registry.flows.ExtensionManager;
|
||||
import google.registry.flows.FlowModule.ClientId;
|
||||
import google.registry.flows.FlowModule.Superuser;
|
||||
import google.registry.flows.FlowModule.TargetId;
|
||||
import google.registry.flows.TransactionalFlow;
|
||||
import google.registry.flows.annotations.ReportingSpec;
|
||||
import google.registry.flows.domain.DomainFlowUtils.NameserversNotSpecifiedForNameserverRestrictedDomainException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.NameserversNotSpecifiedForTldWithNameserverWhitelistException;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingEvent.Flag;
|
||||
import google.registry.model.billing.BillingEvent.Reason;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
import google.registry.model.domain.DomainCommand.Create;
|
||||
import google.registry.model.domain.DomainResource;
|
||||
import google.registry.model.domain.GracePeriod;
|
||||
import google.registry.model.domain.Period;
|
||||
import google.registry.model.domain.allocate.AllocateCreateExtension;
|
||||
import google.registry.model.domain.fee.FeeCreateCommandExtension;
|
||||
import google.registry.model.domain.fee.FeeTransformResponseExtension;
|
||||
import google.registry.model.domain.launch.ApplicationStatus;
|
||||
import google.registry.model.domain.launch.LaunchInfoResponseExtension;
|
||||
import google.registry.model.domain.metadata.MetadataExtension;
|
||||
import google.registry.model.domain.rgp.GracePeriodStatus;
|
||||
import google.registry.model.domain.secdns.SecDnsCreateExtension;
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.eppinput.ResourceCommand;
|
||||
import google.registry.model.eppoutput.CreateData.DomainCreateData;
|
||||
import google.registry.model.eppoutput.EppResponse;
|
||||
import google.registry.model.index.EppResourceIndex;
|
||||
import google.registry.model.index.ForeignKeyIndex;
|
||||
import google.registry.model.ofy.ObjectifyService;
|
||||
import google.registry.model.poll.PendingActionNotificationResponse.DomainPendingActionNotificationResponse;
|
||||
import google.registry.model.poll.PollMessage;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.model.registry.label.ReservationType;
|
||||
import google.registry.model.reporting.DomainTransactionRecord;
|
||||
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import google.registry.tmch.LordnTaskUtils;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/**
|
||||
* An EPP flow that allocates a new domain resource from a domain application.
|
||||
*
|
||||
* <p>Note that this flow is only run by superusers.
|
||||
*
|
||||
* @error {@link google.registry.flows.exceptions.ResourceAlreadyExistsException}
|
||||
* @error {@link DomainAllocateFlow.HasFinalStatusException}
|
||||
* @error {@link DomainAllocateFlow.MissingApplicationException}
|
||||
* @error {@link DomainAllocateFlow.OnlySuperuserCanAllocateException}
|
||||
* @error {@link DomainFlowUtils.ExceedsMaxRegistrationYearsException}
|
||||
* @error {@link DomainFlowUtils.RegistrantNotAllowedException}
|
||||
* @error {@link DomainFlowUtils.NameserversNotAllowedForDomainException}
|
||||
* @error {@link DomainFlowUtils.NameserversNotAllowedForTldException}
|
||||
* @error {@link NameserversNotSpecifiedForNameserverRestrictedDomainException}
|
||||
* @error {@link NameserversNotSpecifiedForTldWithNameserverWhitelistException}
|
||||
*/
|
||||
@ReportingSpec(ActivityReportField.DOMAIN_CREATE) // Allocates are special domain creates.
|
||||
public class DomainAllocateFlow implements TransactionalFlow {
|
||||
|
||||
@Inject ExtensionManager extensionManager;
|
||||
@Inject AuthInfo authInfo;
|
||||
@Inject ResourceCommand resourceCommand;
|
||||
@Inject @ClientId String clientId;
|
||||
@Inject @TargetId String targetId;
|
||||
@Inject @Superuser boolean isSuperuser;
|
||||
@Inject HistoryEntry.Builder historyBuilder;
|
||||
@Inject EppInput eppInput;
|
||||
@Inject Lazy<DnsQueue> dnsQueue;
|
||||
@Inject EppResponse.Builder responseBuilder;
|
||||
@Inject DomainPricingLogic pricingLogic;
|
||||
@Inject DomainAllocateFlow() {}
|
||||
|
||||
@Override
|
||||
public final EppResponse run() throws EppException {
|
||||
extensionManager.register(
|
||||
FeeCreateCommandExtension.class,
|
||||
SecDnsCreateExtension.class,
|
||||
MetadataExtension.class,
|
||||
AllocateCreateExtension.class);
|
||||
extensionManager.validate();
|
||||
validateClientIsLoggedIn(clientId);
|
||||
verifyIsSuperuser();
|
||||
DateTime now = ofy().getTransactionTime();
|
||||
Create command = cloneAndLinkReferences((Create) resourceCommand, now);
|
||||
verifyResourceDoesNotExist(DomainResource.class, targetId, now);
|
||||
InternetDomainName domainName = validateDomainName(command.getFullyQualifiedDomainName());
|
||||
Registry registry = Registry.get(domainName.parent().toString());
|
||||
Period period = command.getPeriod();
|
||||
verifyUnitIsYears(period);
|
||||
int years = period.getValue();
|
||||
validateRegistrationPeriod(years);
|
||||
validateCreateCommandContactsAndNameservers(command, registry, domainName);
|
||||
Optional<SecDnsCreateExtension> secDnsCreate =
|
||||
validateSecDnsExtension(eppInput.getSingleExtension(SecDnsCreateExtension.class));
|
||||
boolean isSunrushAddGracePeriod = isNullOrEmpty(command.getNameservers());
|
||||
AllocateCreateExtension allocateCreate =
|
||||
eppInput.getSingleExtension(AllocateCreateExtension.class).get();
|
||||
DomainApplication application =
|
||||
loadAndValidateApplication(allocateCreate.getApplicationRoid(), now);
|
||||
String repoId = createDomainRepoId(ObjectifyService.allocateId(), registry.getTldStr());
|
||||
ImmutableSet.Builder<ImmutableObject> entitiesToSave = new ImmutableSet.Builder<>();
|
||||
HistoryEntry historyEntry = buildHistoryEntry(
|
||||
repoId, registry.getTldStr(), now, period, registry.getAddGracePeriodLength());
|
||||
entitiesToSave.add(historyEntry);
|
||||
ImmutableSet<? extends ImmutableObject> billsAndPolls = createBillingEventsAndPollMessages(
|
||||
domainName, application, historyEntry, isSunrushAddGracePeriod, registry, now, years);
|
||||
entitiesToSave.addAll(billsAndPolls);
|
||||
DateTime registrationExpirationTime = leapSafeAddYears(now, years);
|
||||
DomainResource newDomain =
|
||||
new DomainResource.Builder()
|
||||
.setCreationClientId(clientId)
|
||||
.setPersistedCurrentSponsorClientId(clientId)
|
||||
.setRepoId(repoId)
|
||||
.setIdnTableName(validateDomainNameWithIdnTables(domainName))
|
||||
.setRegistrationExpirationTime(registrationExpirationTime)
|
||||
.setAutorenewBillingEvent(
|
||||
Key.create(getOnly(billsAndPolls, BillingEvent.Recurring.class)))
|
||||
.setAutorenewPollMessage(
|
||||
Key.create(getOnly(billsAndPolls, PollMessage.Autorenew.class)))
|
||||
.setApplicationTime(allocateCreate.getApplicationTime())
|
||||
.setApplication(Key.create(application))
|
||||
.setSmdId(allocateCreate.getSmdId())
|
||||
.setLaunchNotice(allocateCreate.getNotice())
|
||||
.setDsData(
|
||||
secDnsCreate.isPresent() ? secDnsCreate.get().getDsData() : application.getDsData())
|
||||
.addGracePeriod(
|
||||
createGracePeriod(
|
||||
isSunrushAddGracePeriod, getOnly(billsAndPolls, BillingEvent.OneTime.class)))
|
||||
// Names on the collision list will not be delegated. Set server hold.
|
||||
.setStatusValues(
|
||||
getReservationTypes(domainName).contains(ReservationType.NAME_COLLISION)
|
||||
? ImmutableSet.of(StatusValue.SERVER_HOLD)
|
||||
: ImmutableSet.of())
|
||||
.setRegistrant(command.getRegistrant())
|
||||
.setAuthInfo(command.getAuthInfo())
|
||||
.setFullyQualifiedDomainName(targetId)
|
||||
.setNameservers(command.getNameservers())
|
||||
.setContacts(command.getContacts())
|
||||
.build();
|
||||
entitiesToSave.add(
|
||||
newDomain,
|
||||
buildApplicationHistory(application, now),
|
||||
updateApplication(application),
|
||||
ForeignKeyIndex.create(newDomain, newDomain.getDeletionTime()),
|
||||
EppResourceIndex.create(Key.create(newDomain)));
|
||||
ofy().save().entities(entitiesToSave.build());
|
||||
enqueueTasks(allocateCreate, newDomain);
|
||||
return responseBuilder
|
||||
.setResData(DomainCreateData.create(targetId, now, registrationExpirationTime))
|
||||
.setExtensions(createResponseExtensions(now, registry, years))
|
||||
.build();
|
||||
}
|
||||
|
||||
private <T extends ImmutableObject> T getOnly(
|
||||
Iterable<? extends ImmutableObject> objects, Class<T> clazz) {
|
||||
return Streams.stream(objects)
|
||||
.filter(clazz::isInstance)
|
||||
.map(clazz::cast)
|
||||
.collect(onlyElement());
|
||||
}
|
||||
|
||||
private void verifyIsSuperuser() throws OnlySuperuserCanAllocateException {
|
||||
if (!isSuperuser) {
|
||||
throw new OnlySuperuserCanAllocateException();
|
||||
}
|
||||
}
|
||||
|
||||
private DomainApplication loadAndValidateApplication(
|
||||
String applicationRoid, DateTime now) throws EppException {
|
||||
DomainApplication application =
|
||||
loadDomainApplication(applicationRoid, now)
|
||||
.orElseThrow(() -> new MissingApplicationException(applicationRoid));
|
||||
if (application.getApplicationStatus().isFinalStatus()) {
|
||||
throw new HasFinalStatusException();
|
||||
}
|
||||
return application;
|
||||
}
|
||||
|
||||
private HistoryEntry buildHistoryEntry(
|
||||
String repoId, String tld, DateTime now, Period period, Duration addGracePeriod) {
|
||||
return historyBuilder
|
||||
.setType(HistoryEntry.Type.DOMAIN_ALLOCATE)
|
||||
.setPeriod(period)
|
||||
.setModificationTime(now)
|
||||
.setParent(Key.create(DomainResource.class, repoId))
|
||||
.setDomainTransactionRecords(
|
||||
ImmutableSet.of(
|
||||
DomainTransactionRecord.create(
|
||||
tld,
|
||||
now.plus(addGracePeriod),
|
||||
TransactionReportField.netAddsFieldFromYears(period.getValue()),
|
||||
1)))
|
||||
.build();
|
||||
}
|
||||
|
||||
private ImmutableSet<? extends ImmutableObject> createBillingEventsAndPollMessages(
|
||||
InternetDomainName domainName,
|
||||
DomainApplication application,
|
||||
HistoryEntry historyEntry,
|
||||
boolean isSunrushAddGracePeriod,
|
||||
Registry registry,
|
||||
DateTime now,
|
||||
int years) {
|
||||
DateTime registrationExpirationTime = leapSafeAddYears(now, years);
|
||||
BillingEvent.OneTime oneTimeBillingEvent = createOneTimeBillingEvent(
|
||||
application, historyEntry, isSunrushAddGracePeriod, registry, now, years);
|
||||
PollMessage.OneTime oneTimePollMessage =
|
||||
createOneTimePollMessage(application, historyEntry, getReservationTypes(domainName), now);
|
||||
// Create a new autorenew billing event and poll message starting at the expiration time.
|
||||
BillingEvent.Recurring autorenewBillingEvent =
|
||||
createAutorenewBillingEvent(historyEntry, registrationExpirationTime);
|
||||
PollMessage.Autorenew autorenewPollMessage =
|
||||
createAutorenewPollMessage(historyEntry, registrationExpirationTime);
|
||||
return ImmutableSet.of(
|
||||
oneTimePollMessage,
|
||||
oneTimeBillingEvent,
|
||||
autorenewBillingEvent,
|
||||
autorenewPollMessage);
|
||||
}
|
||||
|
||||
private BillingEvent.OneTime createOneTimeBillingEvent(
|
||||
DomainApplication application,
|
||||
HistoryEntry historyEntry,
|
||||
boolean isSunrushAddGracePeriod,
|
||||
Registry registry,
|
||||
DateTime now,
|
||||
int years) {
|
||||
return new BillingEvent.OneTime.Builder()
|
||||
.setReason(Reason.CREATE)
|
||||
.setFlags(ImmutableSet.of(
|
||||
Flag.ALLOCATION,
|
||||
application.getEncodedSignedMarks().isEmpty() ? Flag.LANDRUSH : Flag.SUNRISE))
|
||||
.setTargetId(targetId)
|
||||
.setClientId(clientId)
|
||||
// Note that the cost is calculated as of now, i.e. the event time, not the billing time,
|
||||
// which may be some additional days into the future.
|
||||
.setCost(getDomainCreateCost(targetId, now, years))
|
||||
.setPeriodYears(years)
|
||||
.setEventTime(now)
|
||||
// If there are no nameservers on the domain, then they get the benefit of the sunrush
|
||||
// add grace period, which is longer than the standard add grace period.
|
||||
.setBillingTime(now.plus(isSunrushAddGracePeriod
|
||||
? registry.getSunrushAddGracePeriodLength()
|
||||
: registry.getAddGracePeriodLength()))
|
||||
.setParent(historyEntry)
|
||||
.build();
|
||||
}
|
||||
|
||||
private BillingEvent.Recurring createAutorenewBillingEvent(
|
||||
HistoryEntry historyEntry, DateTime registrationExpirationTime) {
|
||||
return new BillingEvent.Recurring.Builder()
|
||||
.setReason(Reason.RENEW)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setTargetId(targetId)
|
||||
.setClientId(clientId)
|
||||
.setEventTime(registrationExpirationTime)
|
||||
.setRecurrenceEndTime(END_OF_TIME)
|
||||
.setParent(historyEntry)
|
||||
.build();
|
||||
}
|
||||
|
||||
private PollMessage.Autorenew createAutorenewPollMessage(
|
||||
HistoryEntry historyEntry, DateTime registrationExpirationTime) {
|
||||
return new PollMessage.Autorenew.Builder()
|
||||
.setTargetId(targetId)
|
||||
.setClientId(clientId)
|
||||
.setEventTime(registrationExpirationTime)
|
||||
.setMsg("Domain was auto-renewed.")
|
||||
.setParent(historyEntry)
|
||||
.build();
|
||||
}
|
||||
|
||||
private static GracePeriod createGracePeriod(boolean isSunrushAddGracePeriod,
|
||||
BillingEvent.OneTime oneTimeBillingEvent) {
|
||||
return GracePeriod.forBillingEvent(
|
||||
isSunrushAddGracePeriod ? GracePeriodStatus.SUNRUSH_ADD : GracePeriodStatus.ADD,
|
||||
oneTimeBillingEvent);
|
||||
}
|
||||
|
||||
/** Create a history entry (with no xml or trid) to record that we updated the application. */
|
||||
private static HistoryEntry buildApplicationHistory(DomainApplication application, DateTime now) {
|
||||
return new HistoryEntry.Builder()
|
||||
.setType(HistoryEntry.Type.DOMAIN_APPLICATION_STATUS_UPDATE)
|
||||
.setParent(application)
|
||||
.setModificationTime(now)
|
||||
.setClientId(application.getCurrentSponsorClientId())
|
||||
.setBySuperuser(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
/** Update the application itself. */
|
||||
private DomainApplication updateApplication(DomainApplication application) {
|
||||
return application.asBuilder()
|
||||
.setApplicationStatus(ApplicationStatus.ALLOCATED)
|
||||
.removeStatusValue(StatusValue.PENDING_CREATE)
|
||||
.build();
|
||||
}
|
||||
|
||||
/** Create a poll message informing the registrar that the application status was updated. */
|
||||
private PollMessage.OneTime createOneTimePollMessage(
|
||||
DomainApplication application,
|
||||
HistoryEntry historyEntry,
|
||||
Set<ReservationType> reservationTypes,
|
||||
DateTime now) {
|
||||
return new PollMessage.OneTime.Builder()
|
||||
.setClientId(historyEntry.getClientId())
|
||||
.setEventTime(now)
|
||||
.setMsg(
|
||||
reservationTypes.contains(ReservationType.NAME_COLLISION)
|
||||
? COLLISION_MESSAGE // Remind the registrar of the name collision policy.
|
||||
: "Domain was allocated")
|
||||
.setResponseData(
|
||||
ImmutableList.of(
|
||||
DomainPendingActionNotificationResponse.create(
|
||||
targetId, true, application.getCreationTrid(), now)))
|
||||
.setResponseExtensions(
|
||||
ImmutableList.of(
|
||||
new LaunchInfoResponseExtension.Builder()
|
||||
.setApplicationId(application.getForeignKey())
|
||||
.setPhase(application.getPhase())
|
||||
.setApplicationStatus(ApplicationStatus.ALLOCATED)
|
||||
.build()))
|
||||
.setParent(historyEntry)
|
||||
.build();
|
||||
}
|
||||
|
||||
private void enqueueTasks(AllocateCreateExtension allocateCreate, DomainResource newDomain) {
|
||||
if (newDomain.shouldPublishToDns()) {
|
||||
dnsQueue.get().addDomainRefreshTask(newDomain.getFullyQualifiedDomainName());
|
||||
}
|
||||
if (allocateCreate.getSmdId() != null || allocateCreate.getNotice() != null) {
|
||||
LordnTaskUtils.enqueueDomainResourceTask(newDomain);
|
||||
}
|
||||
}
|
||||
|
||||
private ImmutableList<FeeTransformResponseExtension> createResponseExtensions(
|
||||
DateTime now, Registry registry, int years) throws EppException {
|
||||
FeesAndCredits feesAndCredits =
|
||||
pricingLogic.getCreatePrice(registry, targetId, now, years, false);
|
||||
Optional<FeeCreateCommandExtension> feeCreate =
|
||||
eppInput.getSingleExtension(FeeCreateCommandExtension.class);
|
||||
return feeCreate.isPresent()
|
||||
? ImmutableList.of(createFeeCreateResponse(feeCreate.get(), feesAndCredits))
|
||||
: ImmutableList.of();
|
||||
}
|
||||
|
||||
/** Domain application with specific ROID does not exist. */
|
||||
static class MissingApplicationException extends ObjectDoesNotExistException {
|
||||
public MissingApplicationException(String applicationRoid) {
|
||||
super(DomainApplication.class, applicationRoid);
|
||||
}
|
||||
}
|
||||
|
||||
/** Domain application already has a final status. */
|
||||
static class HasFinalStatusException extends StatusProhibitsOperationException {
|
||||
public HasFinalStatusException() {
|
||||
super("Domain application already has a final status");
|
||||
}
|
||||
}
|
||||
|
||||
/** Only a superuser can allocate domains. */
|
||||
static class OnlySuperuserCanAllocateException extends AuthorizationErrorException {
|
||||
public OnlySuperuserCanAllocateException() {
|
||||
super("Only a superuser can allocate domains");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,420 +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.flows.domain;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.collect.Iterables.getOnlyElement;
|
||||
import static google.registry.flows.FlowUtils.persistEntityChanges;
|
||||
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyResourceDoesNotExist;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.cloneAndLinkReferences;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.createFeeCreateResponse;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.isAnchorTenant;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateCreateCommandContactsAndNameservers;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateDomainName;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateDomainNameWithIdnTables;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateFeeChallenge;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateLaunchCreateNotice;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateRegistrationPeriod;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateSecDnsExtension;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyClaimsNoticeIfAndOnlyIfNeeded;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyClaimsPeriodNotEnded;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyLaunchPhaseMatchesRegistryPhase;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyNoCodeMarks;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyNotReserved;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyPremiumNameIsNotBlocked;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyRegistrarIsActive;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyRegistryStateAllowsApplicationFlows;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyUnitIsYears;
|
||||
import static google.registry.model.EppResourceUtils.createDomainRepoId;
|
||||
import static google.registry.model.index.DomainApplicationIndex.loadActiveApplicationsByDomainName;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.net.InternetDomainName;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppException.CommandUseErrorException;
|
||||
import google.registry.flows.EppException.ObjectAlreadyExistsException;
|
||||
import google.registry.flows.EppException.RequiredParameterMissingException;
|
||||
import google.registry.flows.ExtensionManager;
|
||||
import google.registry.flows.FlowModule.ClientId;
|
||||
import google.registry.flows.FlowModule.Superuser;
|
||||
import google.registry.flows.FlowModule.TargetId;
|
||||
import google.registry.flows.TransactionalFlow;
|
||||
import google.registry.flows.annotations.ReportingSpec;
|
||||
import google.registry.flows.custom.DomainApplicationCreateFlowCustomLogic;
|
||||
import google.registry.flows.custom.DomainApplicationCreateFlowCustomLogic.AfterValidationParameters;
|
||||
import google.registry.flows.custom.DomainApplicationCreateFlowCustomLogic.BeforeResponseParameters;
|
||||
import google.registry.flows.custom.DomainApplicationCreateFlowCustomLogic.BeforeResponseReturnData;
|
||||
import google.registry.flows.custom.EntityChanges;
|
||||
import google.registry.flows.domain.DomainFlowUtils.NameserversNotSpecifiedForNameserverRestrictedDomainException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.NameserversNotSpecifiedForTldWithNameserverWhitelistException;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
import google.registry.model.domain.DomainCommand.Create;
|
||||
import google.registry.model.domain.DomainResource;
|
||||
import google.registry.model.domain.Period;
|
||||
import google.registry.model.domain.fee.FeeCreateCommandExtension;
|
||||
import google.registry.model.domain.fee.FeeTransformCommandExtension;
|
||||
import google.registry.model.domain.launch.ApplicationStatus;
|
||||
import google.registry.model.domain.launch.LaunchCreateExtension;
|
||||
import google.registry.model.domain.launch.LaunchCreateResponseExtension;
|
||||
import google.registry.model.domain.launch.LaunchPhase;
|
||||
import google.registry.model.domain.metadata.MetadataExtension;
|
||||
import google.registry.model.domain.secdns.SecDnsCreateExtension;
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.eppcommon.Trid;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.eppinput.ResourceCommand;
|
||||
import google.registry.model.eppoutput.CreateData.DomainCreateData;
|
||||
import google.registry.model.eppoutput.EppResponse;
|
||||
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
|
||||
import google.registry.model.index.DomainApplicationIndex;
|
||||
import google.registry.model.index.EppResourceIndex;
|
||||
import google.registry.model.ofy.ObjectifyService;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.model.registry.Registry.TldState;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import google.registry.model.smd.EncodedSignedMark;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* An EPP flow that creates a new application for a domain resource.
|
||||
*
|
||||
* @error {@link google.registry.flows.exceptions.ResourceAlreadyExistsException}
|
||||
* @error {@link google.registry.flows.EppException.UnimplementedExtensionException}
|
||||
* @error {@link DomainApplicationCreateFlow.LandrushApplicationDisallowedDuringSunriseException}
|
||||
* @error {@link DomainApplicationCreateFlow.NoticeCannotBeUsedWithSignedMarkException}
|
||||
* @error {@link DomainApplicationCreateFlow.SunriseApplicationDisallowedDuringLandrushException}
|
||||
* @error {@link
|
||||
* DomainApplicationCreateFlow.UncontestedSunriseApplicationBlockedInLandrushException}
|
||||
* @error {@link DomainFlowUtils.AcceptedTooLongAgoException}
|
||||
* @error {@link DomainFlowUtils.BadCommandForRegistryPhaseException}
|
||||
* @error {@link DomainFlowUtils.BadDomainNameCharacterException}
|
||||
* @error {@link DomainFlowUtils.BadDomainNamePartsCountException}
|
||||
* @error {@link DomainFlowUtils.DomainNameExistsAsTldException}
|
||||
* @error {@link DomainFlowUtils.BadPeriodUnitException}
|
||||
* @error {@link DomainFlowTmchUtils.Base64RequiredForEncodedSignedMarksException}
|
||||
* @error {@link DomainFlowUtils.ClaimsPeriodEndedException}
|
||||
* @error {@link DomainFlowUtils.CurrencyUnitMismatchException}
|
||||
* @error {@link DomainFlowUtils.CurrencyValueScaleException}
|
||||
* @error {@link DomainFlowUtils.DashesInThirdAndFourthException}
|
||||
* @error {@link DomainFlowUtils.DomainLabelTooLongException}
|
||||
* @error {@link DomainFlowUtils.DomainReservedException}
|
||||
* @error {@link DomainFlowUtils.DuplicateContactForRoleException}
|
||||
* @error {@link DomainFlowUtils.EmptyDomainNamePartException}
|
||||
* @error {@link DomainFlowUtils.ExceedsMaxRegistrationYearsException}
|
||||
* @error {@link DomainFlowUtils.ExpiredClaimException}
|
||||
* @error {@link DomainFlowUtils.FeesMismatchException}
|
||||
* @error {@link DomainFlowUtils.FeesRequiredForPremiumNameException}
|
||||
* @error {@link DomainFlowUtils.InvalidIdnDomainLabelException}
|
||||
* @error {@link DomainFlowUtils.InvalidPunycodeException}
|
||||
* @error {@link DomainFlowUtils.InvalidTcnIdChecksumException}
|
||||
* @error {@link DomainFlowUtils.InvalidTrademarkValidatorException}
|
||||
* @error {@link DomainFlowUtils.LaunchPhaseMismatchException}
|
||||
* @error {@link DomainFlowUtils.LeadingDashException}
|
||||
* @error {@link DomainFlowUtils.LinkedResourcesDoNotExistException}
|
||||
* @error {@link DomainFlowUtils.MalformedTcnIdException}
|
||||
* @error {@link DomainFlowUtils.MaxSigLifeNotSupportedException}
|
||||
* @error {@link DomainFlowUtils.MissingClaimsNoticeException}
|
||||
* @error {@link DomainFlowUtils.MissingContactTypeException}
|
||||
* @error {@link DomainFlowUtils.NameserversNotAllowedForDomainException}
|
||||
* @error {@link DomainFlowUtils.NameserversNotAllowedForTldException}
|
||||
* @error {@link NameserversNotSpecifiedForNameserverRestrictedDomainException}
|
||||
* @error {@link NameserversNotSpecifiedForTldWithNameserverWhitelistException}
|
||||
* @error {@link DomainFlowTmchUtils.NoMarksFoundMatchingDomainException}
|
||||
* @error {@link DomainFlowTmchUtils.FoundMarkNotYetValidException}
|
||||
* @error {@link DomainFlowTmchUtils.FoundMarkExpiredException}
|
||||
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
|
||||
* @error {@link DomainFlowUtils.PremiumNameBlockedException}
|
||||
* @error {@link DomainFlowUtils.RegistrantNotAllowedException}
|
||||
* @error {@link DomainFlowUtils.RegistrarMustBeActiveForThisOperationException}
|
||||
* @error {@link DomainFlowTmchUtils.SignedMarksMustBeEncodedException}
|
||||
* @error {@link DomainFlowTmchUtils.SignedMarkCertificateExpiredException}
|
||||
* @error {@link DomainFlowTmchUtils.SignedMarkCertificateInvalidException}
|
||||
* @error {@link DomainFlowTmchUtils.SignedMarkCertificateNotYetValidException}
|
||||
* @error {@link DomainFlowTmchUtils.SignedMarkCertificateRevokedException}
|
||||
* @error {@link DomainFlowTmchUtils.SignedMarkCertificateSignatureException}
|
||||
* @error {@link DomainFlowTmchUtils.SignedMarkEncodingErrorException}
|
||||
* @error {@link DomainFlowTmchUtils.SignedMarkParsingErrorException}
|
||||
* @error {@link DomainFlowTmchUtils.SignedMarkRevokedErrorException}
|
||||
* @error {@link DomainFlowTmchUtils.SignedMarkSignatureException}
|
||||
* @error {@link DomainFlowUtils.TldDoesNotExistException}
|
||||
* @error {@link DomainFlowUtils.TooManyDsRecordsException}
|
||||
* @error {@link DomainFlowUtils.TooManyNameserversException}
|
||||
* @error {@link DomainFlowTmchUtils.TooManySignedMarksException}
|
||||
* @error {@link DomainFlowUtils.TrailingDashException}
|
||||
* @error {@link DomainFlowUtils.UnexpectedClaimsNoticeException}
|
||||
* @error {@link DomainFlowUtils.UnsupportedFeeAttributeException}
|
||||
* @error {@link DomainFlowUtils.UnsupportedMarkTypeException}
|
||||
*/
|
||||
@ReportingSpec(ActivityReportField.DOMAIN_CREATE) // Applications are technically domains in EPP.
|
||||
public final class DomainApplicationCreateFlow implements TransactionalFlow {
|
||||
|
||||
@Inject ExtensionManager extensionManager;
|
||||
@Inject EppInput eppInput;
|
||||
@Inject AuthInfo authInfo;
|
||||
@Inject ResourceCommand resourceCommand;
|
||||
@Inject @ClientId String clientId;
|
||||
@Inject @TargetId String targetId;
|
||||
@Inject @Superuser boolean isSuperuser;
|
||||
@Inject HistoryEntry.Builder historyBuilder;
|
||||
@Inject Trid trid;
|
||||
@Inject EppResponse.Builder responseBuilder;
|
||||
@Inject DomainApplicationCreateFlowCustomLogic flowCustomLogic;
|
||||
@Inject DomainFlowTmchUtils tmchUtils;
|
||||
@Inject DomainPricingLogic pricingLogic;
|
||||
@Inject DomainApplicationCreateFlow() {}
|
||||
|
||||
@Override
|
||||
public final EppResponse run() throws EppException {
|
||||
extensionManager.register(
|
||||
FeeCreateCommandExtension.class,
|
||||
SecDnsCreateExtension.class,
|
||||
MetadataExtension.class,
|
||||
LaunchCreateExtension.class);
|
||||
flowCustomLogic.beforeValidation();
|
||||
extensionManager.validate();
|
||||
validateClientIsLoggedIn(clientId);
|
||||
verifyRegistrarIsActive(clientId);
|
||||
DateTime now = ofy().getTransactionTime();
|
||||
Create command = cloneAndLinkReferences((Create) resourceCommand, now);
|
||||
// Fail if the domain is already registered (e.g. this is a landrush application but the domain
|
||||
// was awarded at the end of sunrise). However, multiple domain applications can be created for
|
||||
// the same domain name, so don't try to load an existing application.
|
||||
verifyResourceDoesNotExist(DomainResource.class, targetId, now);
|
||||
// Validate that this is actually a legal domain name on a TLD that the registrar has access to.
|
||||
InternetDomainName domainName = validateDomainName(targetId);
|
||||
String idnTableName = validateDomainNameWithIdnTables(domainName);
|
||||
String tld = domainName.parent().toString();
|
||||
if (!isSuperuser) {
|
||||
// Access to the TLD should be checked before the subsequent checks as it is a greater concern
|
||||
checkAllowedAccessToTld(clientId, tld);
|
||||
}
|
||||
Registry registry = Registry.get(tld);
|
||||
boolean isAnchorTenant =
|
||||
isAnchorTenant(domainName, Optional.empty(), authInfo.getPw().getValue(), Optional.empty());
|
||||
FeesAndCredits feesAndCredits =
|
||||
pricingLogic.getCreatePrice(
|
||||
registry, targetId, now, command.getPeriod().getValue(), isAnchorTenant);
|
||||
verifyUnitIsYears(command.getPeriod());
|
||||
int years = command.getPeriod().getValue();
|
||||
validateRegistrationPeriod(years);
|
||||
validateCreateCommandContactsAndNameservers(command, registry, domainName);
|
||||
LaunchCreateExtension launchCreate =
|
||||
eppInput.getSingleExtension(LaunchCreateExtension.class).get();
|
||||
validateLaunchCreateExtension(launchCreate, registry, domainName, now);
|
||||
// Superusers can create reserved domains, force creations on domains that require a claims
|
||||
// notice without specifying a claims key, and override blocks on registering premium domains.
|
||||
if (!isSuperuser) {
|
||||
verifyPremiumNameIsNotBlocked(targetId, now, clientId);
|
||||
prohibitLandrushIfExactlyOneSunrise(registry, now);
|
||||
if (!isAnchorTenant) {
|
||||
boolean isSunriseApplication = !launchCreate.getSignedMarks().isEmpty();
|
||||
verifyNotReserved(domainName, isSunriseApplication);
|
||||
}
|
||||
}
|
||||
Optional<FeeCreateCommandExtension> feeCreate =
|
||||
eppInput.getSingleExtension(FeeCreateCommandExtension.class);
|
||||
validateFeeChallenge(targetId, tld, clientId, now, feeCreate, feesAndCredits);
|
||||
Optional<SecDnsCreateExtension> secDnsCreate =
|
||||
validateSecDnsExtension(eppInput.getSingleExtension(SecDnsCreateExtension.class));
|
||||
flowCustomLogic.afterValidation(
|
||||
AfterValidationParameters.newBuilder()
|
||||
.setDomainName(domainName)
|
||||
.setYears(years)
|
||||
.build());
|
||||
DomainApplication newApplication =
|
||||
new DomainApplication.Builder()
|
||||
.setCreationTrid(trid)
|
||||
.setCreationClientId(clientId)
|
||||
.setPersistedCurrentSponsorClientId(clientId)
|
||||
.setRepoId(createDomainRepoId(ObjectifyService.allocateId(), tld))
|
||||
.setLaunchNotice(launchCreate == null ? null : launchCreate.getNotice())
|
||||
.setIdnTableName(idnTableName)
|
||||
.setPhase(launchCreate.getPhase())
|
||||
.setPeriod(command.getPeriod())
|
||||
.setApplicationStatus(ApplicationStatus.VALIDATED)
|
||||
.addStatusValue(StatusValue.PENDING_CREATE)
|
||||
.setDsData(secDnsCreate.isPresent() ? secDnsCreate.get().getDsData() : null)
|
||||
.setRegistrant(command.getRegistrant())
|
||||
.setAuthInfo(command.getAuthInfo())
|
||||
.setFullyQualifiedDomainName(targetId)
|
||||
.setNameservers(command.getNameservers())
|
||||
.setContacts(command.getContacts())
|
||||
.setEncodedSignedMarks(
|
||||
launchCreate
|
||||
.getSignedMarks()
|
||||
.stream()
|
||||
.map(abstractSignedMark -> (EncodedSignedMark) abstractSignedMark)
|
||||
.collect(toImmutableList()))
|
||||
.build();
|
||||
HistoryEntry historyEntry =
|
||||
buildHistoryEntry(newApplication.getRepoId(), command.getPeriod(), now);
|
||||
ImmutableSet.Builder<ImmutableObject> entitiesToSave = new ImmutableSet.Builder<>();
|
||||
entitiesToSave.add(
|
||||
newApplication,
|
||||
historyEntry,
|
||||
DomainApplicationIndex.createUpdatedInstance(newApplication),
|
||||
EppResourceIndex.create(Key.create(newApplication)));
|
||||
|
||||
EntityChanges entityChanges =
|
||||
flowCustomLogic.beforeSave(
|
||||
DomainApplicationCreateFlowCustomLogic.BeforeSaveParameters.newBuilder()
|
||||
.setNewApplication(newApplication)
|
||||
.setHistoryEntry(historyEntry)
|
||||
.setEntityChanges(
|
||||
EntityChanges.newBuilder().setSaves(entitiesToSave.build()).build())
|
||||
.setYears(years)
|
||||
.build());
|
||||
persistEntityChanges(entityChanges);
|
||||
BeforeResponseReturnData responseData =
|
||||
flowCustomLogic.beforeResponse(
|
||||
BeforeResponseParameters.newBuilder()
|
||||
.setResData(DomainCreateData.create(targetId, now, null))
|
||||
.setResponseExtensions(
|
||||
createResponseExtensions(
|
||||
newApplication.getForeignKey(),
|
||||
launchCreate.getPhase(),
|
||||
feeCreate,
|
||||
feesAndCredits))
|
||||
.build());
|
||||
return responseBuilder
|
||||
.setResData(responseData.resData())
|
||||
.setExtensions(responseData.responseExtensions())
|
||||
.build();
|
||||
}
|
||||
|
||||
private void validateLaunchCreateExtension(
|
||||
LaunchCreateExtension launchCreate,
|
||||
Registry registry,
|
||||
InternetDomainName domainName,
|
||||
DateTime now) throws EppException {
|
||||
verifyNoCodeMarks(launchCreate);
|
||||
boolean hasClaimsNotice = launchCreate.getNotice() != null;
|
||||
if (hasClaimsNotice) {
|
||||
verifyClaimsPeriodNotEnded(registry, now);
|
||||
}
|
||||
boolean isSunriseApplication = !launchCreate.getSignedMarks().isEmpty();
|
||||
if (!isSuperuser) { // Superusers can ignore the phase.
|
||||
verifyRegistryStateAllowsApplicationFlows(registry, now);
|
||||
verifyLaunchPhaseMatchesRegistryPhase(registry, launchCreate, now);
|
||||
}
|
||||
if (now.isBefore(registry.getClaimsPeriodEnd())) {
|
||||
verifyClaimsNoticeIfAndOnlyIfNeeded(domainName, isSunriseApplication, hasClaimsNotice);
|
||||
}
|
||||
TldState tldState = registry.getTldState(now);
|
||||
if (launchCreate.getSignedMarks().isEmpty()) {
|
||||
// During sunrise, a signed mark is required since only trademark holders are allowed to
|
||||
// create an application. However, we found no marks (ie, this was a landrush application).
|
||||
if (tldState == TldState.SUNRISE) {
|
||||
throw new LandrushApplicationDisallowedDuringSunriseException();
|
||||
}
|
||||
} else {
|
||||
if (hasClaimsNotice) { // Can't use a claims notice id with a signed mark.
|
||||
throw new NoticeCannotBeUsedWithSignedMarkException();
|
||||
}
|
||||
if (tldState == TldState.LANDRUSH) {
|
||||
throw new SunriseApplicationDisallowedDuringLandrushException();
|
||||
}
|
||||
}
|
||||
String domainLabel = domainName.parts().get(0);
|
||||
validateLaunchCreateNotice(launchCreate.getNotice(), domainLabel, isSuperuser, now);
|
||||
// If a signed mark was provided, then it must match the desired domain label.
|
||||
if (!launchCreate.getSignedMarks().isEmpty()) {
|
||||
tmchUtils.verifySignedMarks(launchCreate.getSignedMarks(), domainLabel, now);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prohibit creating a landrush application in LANDRUSH (but not in SUNRUSH) if there is exactly
|
||||
* one sunrise application for the same name.
|
||||
*/
|
||||
private void prohibitLandrushIfExactlyOneSunrise(Registry registry, DateTime now)
|
||||
throws UncontestedSunriseApplicationBlockedInLandrushException {
|
||||
if (registry.getTldState(now) == TldState.LANDRUSH) {
|
||||
ImmutableSet<DomainApplication> applications =
|
||||
loadActiveApplicationsByDomainName(targetId, now);
|
||||
if (applications.size() == 1
|
||||
&& getOnlyElement(applications).getPhase().equals(LaunchPhase.SUNRISE)) {
|
||||
throw new UncontestedSunriseApplicationBlockedInLandrushException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private HistoryEntry buildHistoryEntry(String repoId, Period period, DateTime now) {
|
||||
return historyBuilder
|
||||
.setType(HistoryEntry.Type.DOMAIN_APPLICATION_CREATE)
|
||||
.setPeriod(period)
|
||||
.setModificationTime(now)
|
||||
.setParent(Key.create(DomainApplication.class, repoId))
|
||||
.build();
|
||||
}
|
||||
|
||||
private static ImmutableList<ResponseExtension> createResponseExtensions(
|
||||
String applicationId,
|
||||
LaunchPhase launchPhase,
|
||||
Optional<? extends FeeTransformCommandExtension> feeCreate,
|
||||
FeesAndCredits feesAndCredits) {
|
||||
ImmutableList.Builder<ResponseExtension> responseExtensionsBuilder =
|
||||
new ImmutableList.Builder<>();
|
||||
responseExtensionsBuilder.add(new LaunchCreateResponseExtension.Builder()
|
||||
.setPhase(launchPhase)
|
||||
.setApplicationId(applicationId)
|
||||
.build());
|
||||
if (feeCreate.isPresent()) {
|
||||
responseExtensionsBuilder.add(createFeeCreateResponse(feeCreate.get(), feesAndCredits));
|
||||
}
|
||||
return responseExtensionsBuilder.build();
|
||||
}
|
||||
|
||||
/** Landrush applications are disallowed during sunrise. */
|
||||
static class LandrushApplicationDisallowedDuringSunriseException
|
||||
extends RequiredParameterMissingException {
|
||||
public LandrushApplicationDisallowedDuringSunriseException() {
|
||||
super("Landrush applications are disallowed during sunrise");
|
||||
}
|
||||
}
|
||||
|
||||
/** A notice cannot be specified when using a signed mark. */
|
||||
static class NoticeCannotBeUsedWithSignedMarkException extends CommandUseErrorException {
|
||||
public NoticeCannotBeUsedWithSignedMarkException() {
|
||||
super("A notice cannot be specified when using a signed mark");
|
||||
}
|
||||
}
|
||||
|
||||
/** Sunrise applications are disallowed during landrush. */
|
||||
static class SunriseApplicationDisallowedDuringLandrushException
|
||||
extends CommandUseErrorException {
|
||||
public SunriseApplicationDisallowedDuringLandrushException() {
|
||||
super("Sunrise applications are disallowed during landrush");
|
||||
}
|
||||
}
|
||||
|
||||
/** This name has already been claimed by a sunrise applicant. */
|
||||
static class UncontestedSunriseApplicationBlockedInLandrushException
|
||||
extends ObjectAlreadyExistsException {
|
||||
public UncontestedSunriseApplicationBlockedInLandrushException() {
|
||||
super("This name has already been claimed by a sunrise applicant");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,125 +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.flows.domain;
|
||||
|
||||
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyExistence;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyApplicationDomainMatchesTargetId;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyLaunchPhaseMatchesRegistryPhase;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyRegistryStateAllowsApplicationFlows;
|
||||
import static google.registry.model.EppResourceUtils.loadDomainApplication;
|
||||
import static google.registry.model.ResourceTransferUtils.updateForeignKeyIndexDeletionTime;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppException.StatusProhibitsOperationException;
|
||||
import google.registry.flows.ExtensionManager;
|
||||
import google.registry.flows.FlowModule.ApplicationId;
|
||||
import google.registry.flows.FlowModule.ClientId;
|
||||
import google.registry.flows.FlowModule.Superuser;
|
||||
import google.registry.flows.FlowModule.TargetId;
|
||||
import google.registry.flows.TransactionalFlow;
|
||||
import google.registry.flows.annotations.ReportingSpec;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
import google.registry.model.domain.launch.LaunchDeleteExtension;
|
||||
import google.registry.model.domain.launch.LaunchPhase;
|
||||
import google.registry.model.domain.metadata.MetadataExtension;
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.eppoutput.EppResponse;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.model.registry.Registry.TldState;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* An EPP flow that deletes a domain application.
|
||||
*
|
||||
* @error {@link google.registry.flows.EppException.UnimplementedExtensionException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}
|
||||
* @error {@link DomainApplicationDeleteFlow.SunriseApplicationCannotBeDeletedInLandrushException}
|
||||
* @error {@link DomainFlowUtils.ApplicationDomainNameMismatchException}
|
||||
* @error {@link DomainFlowUtils.BadCommandForRegistryPhaseException}
|
||||
* @error {@link DomainFlowUtils.LaunchPhaseMismatchException}
|
||||
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
|
||||
*/
|
||||
@ReportingSpec(ActivityReportField.DOMAIN_DELETE) // Applications are technically domains in EPP.
|
||||
public final class DomainApplicationDeleteFlow implements TransactionalFlow {
|
||||
|
||||
@Inject ExtensionManager extensionManager;
|
||||
@Inject EppInput eppInput;
|
||||
@Inject Optional<AuthInfo> authInfo;
|
||||
@Inject @ClientId String clientId;
|
||||
@Inject @TargetId String targetId;
|
||||
@Inject @ApplicationId String applicationId;
|
||||
@Inject @Superuser boolean isSuperuser;
|
||||
@Inject HistoryEntry.Builder historyBuilder;
|
||||
@Inject EppResponse.Builder responseBuilder;
|
||||
@Inject DomainApplicationDeleteFlow() {}
|
||||
|
||||
@Override
|
||||
public final EppResponse run() throws EppException {
|
||||
extensionManager.register(MetadataExtension.class, LaunchDeleteExtension.class);
|
||||
extensionManager.validate();
|
||||
validateClientIsLoggedIn(clientId);
|
||||
DateTime now = ofy().getTransactionTime();
|
||||
DomainApplication existingApplication = verifyExistence(
|
||||
DomainApplication.class, applicationId, loadDomainApplication(applicationId, now));
|
||||
verifyApplicationDomainMatchesTargetId(existingApplication, targetId);
|
||||
verifyOptionalAuthInfo(authInfo, existingApplication);
|
||||
String tld = existingApplication.getTld();
|
||||
if (!isSuperuser) {
|
||||
checkAllowedAccessToTld(clientId, tld);
|
||||
Registry registry = Registry.get(tld);
|
||||
verifyRegistryStateAllowsApplicationFlows(registry, now);
|
||||
verifyLaunchPhaseMatchesRegistryPhase(
|
||||
registry, eppInput.getSingleExtension(LaunchDeleteExtension.class).get(), now);
|
||||
verifyResourceOwnership(clientId, existingApplication);
|
||||
// Don't allow deleting a sunrise application during landrush.
|
||||
if (existingApplication.getPhase().equals(LaunchPhase.SUNRISE)
|
||||
&& registry.getTldState(now).equals(TldState.LANDRUSH)) {
|
||||
throw new SunriseApplicationCannotBeDeletedInLandrushException();
|
||||
}
|
||||
}
|
||||
DomainApplication newApplication = existingApplication.asBuilder()
|
||||
.setDeletionTime(now)
|
||||
.setStatusValues(null)
|
||||
.build();
|
||||
HistoryEntry historyEntry = historyBuilder
|
||||
.setType(HistoryEntry.Type.DOMAIN_APPLICATION_DELETE)
|
||||
.setModificationTime(now)
|
||||
.setParent(Key.create(existingApplication))
|
||||
.build();
|
||||
updateForeignKeyIndexDeletionTime(newApplication);
|
||||
ofy().save().<Object>entities(newApplication, historyEntry);
|
||||
return responseBuilder.build();
|
||||
}
|
||||
|
||||
/** A sunrise application cannot be deleted during landrush. */
|
||||
static class SunriseApplicationCannotBeDeletedInLandrushException
|
||||
extends StatusProhibitsOperationException {
|
||||
public SunriseApplicationCannotBeDeletedInLandrushException() {
|
||||
super("A sunrise application cannot be deleted during landrush");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,167 +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.flows.domain;
|
||||
|
||||
import static com.google.common.collect.Sets.union;
|
||||
import static google.registry.flows.FlowUtils.unmarshalEpp;
|
||||
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyExistence;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.addSecDnsExtensionIfPresent;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.loadForeignKeyedDesignatedContacts;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyApplicationDomainMatchesTargetId;
|
||||
import static google.registry.model.EppResourceUtils.loadDomainApplication;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppException.ParameterValuePolicyErrorException;
|
||||
import google.registry.flows.EppException.RequiredParameterMissingException;
|
||||
import google.registry.flows.ExtensionManager;
|
||||
import google.registry.flows.Flow;
|
||||
import google.registry.flows.FlowModule.ApplicationId;
|
||||
import google.registry.flows.FlowModule.ClientId;
|
||||
import google.registry.flows.FlowModule.TargetId;
|
||||
import google.registry.flows.annotations.ReportingSpec;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
import google.registry.model.domain.DomainCommand.Info;
|
||||
import google.registry.model.domain.DomainInfoData;
|
||||
import google.registry.model.domain.launch.LaunchInfoExtension;
|
||||
import google.registry.model.domain.launch.LaunchInfoResponseExtension;
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.eppinput.ResourceCommand;
|
||||
import google.registry.model.eppoutput.EppResponse;
|
||||
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
|
||||
import google.registry.model.mark.Mark;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import google.registry.model.smd.EncodedSignedMark;
|
||||
import google.registry.model.smd.SignedMark;
|
||||
import google.registry.util.Clock;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* An EPP flow that returns information about a domain application.
|
||||
*
|
||||
* <p>Only the registrar that owns the application can see its info. The flow can optionally include
|
||||
* delegated hosts in its response.
|
||||
*
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}
|
||||
* @error {@link DomainFlowUtils.ApplicationDomainNameMismatchException}
|
||||
* @error {@link DomainApplicationInfoFlow.ApplicationLaunchPhaseMismatchException}
|
||||
* @error {@link MissingApplicationIdException}
|
||||
*/
|
||||
@ReportingSpec(ActivityReportField.DOMAIN_INFO) // Applications are technically domains in EPP.
|
||||
public final class DomainApplicationInfoFlow implements Flow {
|
||||
|
||||
@Inject ResourceCommand resourceCommand;
|
||||
@Inject ExtensionManager extensionManager;
|
||||
@Inject EppInput eppInput;
|
||||
@Inject Optional<AuthInfo> authInfo;
|
||||
@Inject @ClientId String clientId;
|
||||
@Inject @TargetId String targetId;
|
||||
@Inject @ApplicationId String applicationId;
|
||||
@Inject Clock clock;
|
||||
@Inject EppResponse.Builder responseBuilder;
|
||||
@Inject DomainApplicationInfoFlow() {}
|
||||
|
||||
@Override
|
||||
public final EppResponse run() throws EppException {
|
||||
extensionManager.register(LaunchInfoExtension.class);
|
||||
extensionManager.validate();
|
||||
validateClientIsLoggedIn(clientId);
|
||||
if (applicationId.isEmpty()) {
|
||||
throw new MissingApplicationIdException();
|
||||
}
|
||||
DomainApplication application =
|
||||
verifyExistence(
|
||||
DomainApplication.class,
|
||||
applicationId,
|
||||
loadDomainApplication(applicationId, clock.nowUtc()));
|
||||
verifyApplicationDomainMatchesTargetId(application, targetId);
|
||||
verifyOptionalAuthInfo(authInfo, application);
|
||||
LaunchInfoExtension launchInfo = eppInput.getSingleExtension(LaunchInfoExtension.class).get();
|
||||
if (!application.getPhase().equals(launchInfo.getPhase())) {
|
||||
throw new ApplicationLaunchPhaseMismatchException();
|
||||
}
|
||||
// We don't support authInfo for applications, so if it's another registrar always fail.
|
||||
verifyResourceOwnership(clientId, application);
|
||||
boolean showDelegatedHosts = ((Info) resourceCommand).getHostsRequest().requestDelegated();
|
||||
// Prefetch all referenced resources. Calling values() blocks until loading is done.
|
||||
ofy().load()
|
||||
.values(union(application.getNameservers(), application.getReferencedContacts())).values();
|
||||
return responseBuilder
|
||||
.setResData(DomainInfoData.newBuilder()
|
||||
.setFullyQualifiedDomainName(application.getFullyQualifiedDomainName())
|
||||
.setRepoId(application.getRepoId())
|
||||
.setStatusValues(application.getStatusValues())
|
||||
.setRegistrant(
|
||||
ofy().load().key(application.getRegistrant()).now().getContactId())
|
||||
.setContacts(loadForeignKeyedDesignatedContacts(application.getContacts()))
|
||||
.setNameservers(showDelegatedHosts
|
||||
? application.loadNameserverFullyQualifiedHostNames()
|
||||
: null)
|
||||
.setCurrentSponsorClientId(application.getCurrentSponsorClientId())
|
||||
.setCreationClientId(application.getCreationClientId())
|
||||
.setCreationTime(application.getCreationTime())
|
||||
.setLastEppUpdateClientId(application.getLastEppUpdateClientId())
|
||||
.setLastEppUpdateTime(application.getLastEppUpdateTime())
|
||||
.setAuthInfo(application.getAuthInfo())
|
||||
.build())
|
||||
.setExtensions(getDomainResponseExtensions(application, launchInfo))
|
||||
.build();
|
||||
}
|
||||
|
||||
ImmutableList<ResponseExtension> getDomainResponseExtensions(
|
||||
DomainApplication application, LaunchInfoExtension launchInfo) {
|
||||
ImmutableList.Builder<Mark> marksBuilder = new ImmutableList.Builder<>();
|
||||
if (Boolean.TRUE.equals(launchInfo.getIncludeMark())) { // Default to false.
|
||||
for (EncodedSignedMark encodedMark : application.getEncodedSignedMarks()) {
|
||||
try {
|
||||
marksBuilder.add(unmarshalEpp(SignedMark.class, encodedMark.getBytes()).getMark());
|
||||
} catch (EppException e) {
|
||||
// This is a serious error; don't let the benign EppException propagate.
|
||||
throw new IllegalStateException("Could not decode a stored encoded signed mark", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
ImmutableList.Builder<ResponseExtension> extensions = new ImmutableList.Builder<>();
|
||||
extensions.add(new LaunchInfoResponseExtension.Builder()
|
||||
.setPhase(application.getPhase())
|
||||
.setApplicationId(application.getForeignKey())
|
||||
.setApplicationStatus(application.getApplicationStatus())
|
||||
.setMarks(marksBuilder.build())
|
||||
.build());
|
||||
addSecDnsExtensionIfPresent(extensions, application.getDsData());
|
||||
return extensions.build();
|
||||
}
|
||||
|
||||
/** Application id is required. */
|
||||
static class MissingApplicationIdException extends RequiredParameterMissingException {
|
||||
public MissingApplicationIdException() {
|
||||
super("Application id is required");
|
||||
}
|
||||
}
|
||||
|
||||
/** Declared launch extension phase does not match phase of the application. */
|
||||
static class ApplicationLaunchPhaseMismatchException extends ParameterValuePolicyErrorException {
|
||||
public ApplicationLaunchPhaseMismatchException() {
|
||||
super("Declared launch extension phase does not match the phase of the application");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,263 +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.flows.domain;
|
||||
|
||||
import static com.google.common.base.CaseFormat.LOWER_CAMEL;
|
||||
import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
|
||||
import static com.google.common.base.MoreObjects.firstNonNull;
|
||||
import static com.google.common.collect.Sets.union;
|
||||
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
|
||||
import static google.registry.flows.ResourceFlowUtils.checkSameValuesNotAddedAndRemoved;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyAllStatusesAreClientSettable;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyExistence;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.cloneAndLinkReferences;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.updateDsData;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateContactsHaveTypes;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateDsData;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateFeesAckedIfPresent;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateNameserversAllowedOnDomain;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateNameserversAllowedOnTld;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateNameserversCountForTld;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateNoDuplicateContacts;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateRegistrantAllowedOnTld;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateRequiredContactsPresent;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyApplicationDomainMatchesTargetId;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyClientUpdateNotProhibited;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyNotInPendingDelete;
|
||||
import static google.registry.model.EppResourceUtils.loadDomainApplication;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.util.CollectionUtils.nullToEmpty;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.net.InternetDomainName;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppException.StatusProhibitsOperationException;
|
||||
import google.registry.flows.ExtensionManager;
|
||||
import google.registry.flows.FlowModule.ApplicationId;
|
||||
import google.registry.flows.FlowModule.ClientId;
|
||||
import google.registry.flows.FlowModule.Superuser;
|
||||
import google.registry.flows.FlowModule.TargetId;
|
||||
import google.registry.flows.TransactionalFlow;
|
||||
import google.registry.flows.annotations.ReportingSpec;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
import google.registry.model.domain.DomainCommand.Update;
|
||||
import google.registry.model.domain.DomainCommand.Update.AddRemove;
|
||||
import google.registry.model.domain.DomainCommand.Update.Change;
|
||||
import google.registry.model.domain.fee.FeeUpdateCommandExtension;
|
||||
import google.registry.model.domain.launch.ApplicationStatus;
|
||||
import google.registry.model.domain.launch.LaunchUpdateExtension;
|
||||
import google.registry.model.domain.metadata.MetadataExtension;
|
||||
import google.registry.model.domain.secdns.SecDnsUpdateExtension;
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.eppinput.ResourceCommand;
|
||||
import google.registry.model.eppoutput.EppResponse;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* An EPP flow that updates a domain application.
|
||||
*
|
||||
* <p>Updates can change contacts, nameservers and delegation signer data of an application. Updates
|
||||
* cannot change the domain name that is being applied for.
|
||||
*
|
||||
* @error {@link google.registry.flows.EppException.UnimplementedExtensionException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.StatusNotClientSettableException}
|
||||
* @error {@link google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException}
|
||||
* @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException}
|
||||
* @error {@link DomainFlowUtils.ApplicationDomainNameMismatchException}
|
||||
* @error {@link DomainFlowUtils.DuplicateContactForRoleException}
|
||||
* @error {@link DomainFlowUtils.EmptySecDnsUpdateException}
|
||||
* @error {@link DomainFlowUtils.FeesMismatchException}
|
||||
* @error {@link DomainFlowUtils.LinkedResourcesDoNotExistException}
|
||||
* @error {@link DomainFlowUtils.MaxSigLifeChangeNotSupportedException}
|
||||
* @error {@link DomainFlowUtils.MissingAdminContactException}
|
||||
* @error {@link DomainFlowUtils.MissingContactTypeException}
|
||||
* @error {@link DomainFlowUtils.MissingTechnicalContactException}
|
||||
* @error {@link DomainFlowUtils.NameserversNotAllowedForTldException}
|
||||
* @error {@link DomainFlowUtils.NameserversNotSpecifiedForTldWithNameserverWhitelistException}
|
||||
* @error {@link DomainFlowUtils.NameserversNotAllowedForDomainException}
|
||||
* @error {@link DomainFlowUtils.NameserversNotSpecifiedForNameserverRestrictedDomainException}
|
||||
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
|
||||
* @error {@link DomainFlowUtils.RegistrantNotAllowedException}
|
||||
* @error {@link DomainFlowUtils.SecDnsAllUsageException}
|
||||
* @error {@link DomainFlowUtils.TooManyDsRecordsException}
|
||||
* @error {@link DomainFlowUtils.TooManyNameserversException}
|
||||
* @error {@link DomainFlowUtils.UrgentAttributeNotSupportedException}
|
||||
* @error {@link DomainApplicationUpdateFlow.ApplicationStatusProhibitsUpdateException}
|
||||
*/
|
||||
@ReportingSpec(ActivityReportField.DOMAIN_UPDATE) // Applications are technically domains in EPP.
|
||||
public class DomainApplicationUpdateFlow implements TransactionalFlow {
|
||||
|
||||
/**
|
||||
* Note that CLIENT_UPDATE_PROHIBITED is intentionally not in this list. This is because it
|
||||
* requires special checking, since you must be able to clear the status off the object with an
|
||||
* update.
|
||||
*/
|
||||
private static final ImmutableSet<StatusValue> UPDATE_DISALLOWED_STATUSES =
|
||||
Sets.immutableEnumSet(
|
||||
StatusValue.PENDING_DELETE,
|
||||
StatusValue.SERVER_UPDATE_PROHIBITED);
|
||||
|
||||
private static final ImmutableSet<ApplicationStatus> UPDATE_DISALLOWED_APPLICATION_STATUSES =
|
||||
Sets.immutableEnumSet(
|
||||
ApplicationStatus.INVALID,
|
||||
ApplicationStatus.REJECTED,
|
||||
ApplicationStatus.ALLOCATED);
|
||||
|
||||
@Inject ResourceCommand resourceCommand;
|
||||
@Inject ExtensionManager extensionManager;
|
||||
@Inject EppInput eppInput;
|
||||
@Inject Optional<AuthInfo> authInfo;
|
||||
@Inject @ClientId String clientId;
|
||||
@Inject @TargetId String targetId;
|
||||
@Inject @ApplicationId String applicationId;
|
||||
@Inject @Superuser boolean isSuperuser;
|
||||
@Inject HistoryEntry.Builder historyBuilder;
|
||||
@Inject EppResponse.Builder responseBuilder;
|
||||
@Inject DomainPricingLogic pricingLogic;
|
||||
@Inject DomainApplicationUpdateFlow() {}
|
||||
|
||||
@Override
|
||||
public final EppResponse run() throws EppException {
|
||||
extensionManager.register(
|
||||
FeeUpdateCommandExtension.class,
|
||||
LaunchUpdateExtension.class,
|
||||
MetadataExtension.class,
|
||||
SecDnsUpdateExtension.class);
|
||||
extensionManager.validate();
|
||||
validateClientIsLoggedIn(clientId);
|
||||
DateTime now = ofy().getTransactionTime();
|
||||
Update command = cloneAndLinkReferences((Update) resourceCommand, now);
|
||||
DomainApplication existingApplication = verifyExistence(
|
||||
DomainApplication.class, applicationId, loadDomainApplication(applicationId, now));
|
||||
verifyApplicationDomainMatchesTargetId(existingApplication, targetId);
|
||||
verifyNoDisallowedStatuses(existingApplication, UPDATE_DISALLOWED_STATUSES);
|
||||
verifyOptionalAuthInfo(authInfo, existingApplication);
|
||||
verifyUpdateAllowed(existingApplication, command, now);
|
||||
HistoryEntry historyEntry = buildHistoryEntry(existingApplication, now);
|
||||
DomainApplication newApplication = updateApplication(existingApplication, command, now);
|
||||
validateNewApplication(newApplication);
|
||||
ofy().save().<ImmutableObject>entities(newApplication, historyEntry);
|
||||
return responseBuilder.build();
|
||||
}
|
||||
|
||||
protected final void verifyUpdateAllowed(
|
||||
DomainApplication existingApplication, Update command, DateTime now) throws EppException {
|
||||
AddRemove add = command.getInnerAdd();
|
||||
AddRemove remove = command.getInnerRemove();
|
||||
String tld = existingApplication.getTld();
|
||||
if (!isSuperuser) {
|
||||
verifyResourceOwnership(clientId, existingApplication);
|
||||
verifyClientUpdateNotProhibited(command, existingApplication);
|
||||
verifyAllStatusesAreClientSettable(union(add.getStatusValues(), remove.getStatusValues()));
|
||||
checkAllowedAccessToTld(clientId, tld);
|
||||
}
|
||||
if (UPDATE_DISALLOWED_APPLICATION_STATUSES
|
||||
.contains(existingApplication.getApplicationStatus())) {
|
||||
throw new ApplicationStatusProhibitsUpdateException(
|
||||
existingApplication.getApplicationStatus());
|
||||
}
|
||||
Registry registry = Registry.get(tld);
|
||||
FeesAndCredits feesAndCredits =
|
||||
pricingLogic.getApplicationUpdatePrice(registry, existingApplication, now);
|
||||
Optional<FeeUpdateCommandExtension> feeUpdate =
|
||||
eppInput.getSingleExtension(FeeUpdateCommandExtension.class);
|
||||
validateFeesAckedIfPresent(feeUpdate, feesAndCredits);
|
||||
verifyNotInPendingDelete(
|
||||
add.getContacts(),
|
||||
command.getInnerChange().getRegistrant(),
|
||||
add.getNameservers());
|
||||
validateContactsHaveTypes(add.getContacts());
|
||||
validateContactsHaveTypes(remove.getContacts());
|
||||
validateRegistrantAllowedOnTld(tld, command.getInnerChange().getRegistrantContactId());
|
||||
validateNameserversAllowedOnTld(
|
||||
tld, add.getNameserverFullyQualifiedHostNames());
|
||||
InternetDomainName domainName =
|
||||
InternetDomainName.from(existingApplication.getFullyQualifiedDomainName());
|
||||
validateNameserversAllowedOnDomain(
|
||||
domainName, nullToEmpty(add.getNameserverFullyQualifiedHostNames()));
|
||||
}
|
||||
|
||||
private HistoryEntry buildHistoryEntry(DomainApplication existingApplication, DateTime now) {
|
||||
return historyBuilder
|
||||
.setType(HistoryEntry.Type.DOMAIN_APPLICATION_UPDATE)
|
||||
.setModificationTime(now)
|
||||
.setParent(Key.create(existingApplication))
|
||||
.build();
|
||||
}
|
||||
|
||||
private DomainApplication updateApplication(
|
||||
DomainApplication application, Update command, DateTime now) throws EppException {
|
||||
AddRemove add = command.getInnerAdd();
|
||||
AddRemove remove = command.getInnerRemove();
|
||||
checkSameValuesNotAddedAndRemoved(add.getNameservers(), remove.getNameservers());
|
||||
checkSameValuesNotAddedAndRemoved(add.getContacts(), remove.getContacts());
|
||||
checkSameValuesNotAddedAndRemoved(add.getStatusValues(), remove.getStatusValues());
|
||||
Change change = command.getInnerChange();
|
||||
Optional<SecDnsUpdateExtension> secDnsUpdate =
|
||||
eppInput.getSingleExtension(SecDnsUpdateExtension.class);
|
||||
return application.asBuilder()
|
||||
// Handle the secDNS extension.
|
||||
.setDsData(secDnsUpdate.isPresent()
|
||||
? updateDsData(application.getDsData(), secDnsUpdate.get())
|
||||
: application.getDsData())
|
||||
.setLastEppUpdateTime(now)
|
||||
.setLastEppUpdateClientId(clientId)
|
||||
.addStatusValues(add.getStatusValues())
|
||||
.removeStatusValues(remove.getStatusValues())
|
||||
.addNameservers(add.getNameservers())
|
||||
.removeNameservers(remove.getNameservers())
|
||||
.addContacts(add.getContacts())
|
||||
.removeContacts(remove.getContacts())
|
||||
.setRegistrant(firstNonNull(change.getRegistrant(), application.getRegistrant()))
|
||||
.setAuthInfo(firstNonNull(change.getAuthInfo(), application.getAuthInfo()))
|
||||
.build();
|
||||
}
|
||||
|
||||
private void validateNewApplication(DomainApplication newApplication) throws EppException {
|
||||
validateNoDuplicateContacts(newApplication.getContacts());
|
||||
validateRequiredContactsPresent(newApplication.getRegistrant(), newApplication.getContacts());
|
||||
validateDsData(newApplication.getDsData());
|
||||
validateNameserversCountForTld(
|
||||
newApplication.getTld(),
|
||||
InternetDomainName.from(newApplication.getFullyQualifiedDomainName()),
|
||||
newApplication.getNameservers().size());
|
||||
}
|
||||
|
||||
/** Application status prohibits this domain update. */
|
||||
static class ApplicationStatusProhibitsUpdateException extends StatusProhibitsOperationException {
|
||||
public ApplicationStatusProhibitsUpdateException(ApplicationStatus status) {
|
||||
super(String.format(
|
||||
"Applications in state %s can not be updated",
|
||||
UPPER_UNDERSCORE.to(LOWER_CAMEL, status.name())));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,13 +24,11 @@ import static google.registry.flows.domain.DomainFlowUtils.validateDomainName;
|
|||
import static google.registry.flows.domain.DomainFlowUtils.validateDomainNameWithIdnTables;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyNotInPredelegation;
|
||||
import static google.registry.model.EppResourceUtils.checkResourcesExist;
|
||||
import static google.registry.model.index.DomainApplicationIndex.loadActiveApplicationsByDomainName;
|
||||
import static google.registry.model.registry.label.ReservationType.getTypeOfHighestSeverity;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.net.InternetDomainName;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.flows.EppException;
|
||||
|
@ -58,7 +56,6 @@ import google.registry.model.eppoutput.CheckData.DomainCheckData;
|
|||
import google.registry.model.eppoutput.EppResponse;
|
||||
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.model.registry.Registry.TldState;
|
||||
import google.registry.model.registry.label.ReservationType;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import google.registry.util.Clock;
|
||||
|
@ -99,14 +96,6 @@ import org.joda.time.DateTime;
|
|||
@ReportingSpec(ActivityReportField.DOMAIN_CHECK)
|
||||
public final class DomainCheckFlow implements Flow {
|
||||
|
||||
/**
|
||||
* The TLD states during which we want to report a domain with pending applications as
|
||||
* unavailable.
|
||||
*/
|
||||
private static final ImmutableSet<TldState> PENDING_ALLOCATION_TLD_STATES =
|
||||
Sets.immutableEnumSet(
|
||||
TldState.GENERAL_AVAILABILITY, TldState.START_DATE_SUNRISE, TldState.QUIET_PERIOD);
|
||||
|
||||
@Inject ResourceCommand resourceCommand;
|
||||
@Inject ExtensionManager extensionManager;
|
||||
@Inject EppInput eppInput;
|
||||
|
@ -166,7 +155,7 @@ public final class DomainCheckFlow implements Flow {
|
|||
ImmutableList.Builder<DomainCheck> checks = new ImmutableList.Builder<>();
|
||||
for (String targetId : targetIds) {
|
||||
Optional<String> message =
|
||||
getMessageForCheck(domainNames.get(targetId), existingIds, tokenCheckResults, now);
|
||||
getMessageForCheck(domainNames.get(targetId), existingIds, tokenCheckResults);
|
||||
checks.add(DomainCheck.create(!message.isPresent(), targetId, message.orElse(null)));
|
||||
}
|
||||
BeforeResponseReturnData responseData =
|
||||
|
@ -185,18 +174,10 @@ public final class DomainCheckFlow implements Flow {
|
|||
private Optional<String> getMessageForCheck(
|
||||
InternetDomainName domainName,
|
||||
Set<String> existingIds,
|
||||
ImmutableMap<InternetDomainName, String> tokenCheckResults,
|
||||
DateTime now) {
|
||||
ImmutableMap<InternetDomainName, String> tokenCheckResults) {
|
||||
if (existingIds.contains(domainName.toString())) {
|
||||
return Optional.of("In use");
|
||||
}
|
||||
Registry registry = Registry.get(domainName.parent().toString());
|
||||
if (PENDING_ALLOCATION_TLD_STATES.contains(registry.getTldState(now))
|
||||
&& loadActiveApplicationsByDomainName(domainName.toString(), now)
|
||||
.stream()
|
||||
.anyMatch(input -> !input.getApplicationStatus().isFinalStatus())) {
|
||||
return Optional.of("Pending allocation");
|
||||
}
|
||||
ImmutableSet<ReservationType> reservationTypes = getReservationTypes(domainName);
|
||||
if (!reservationTypes.isEmpty()) {
|
||||
return Optional.of(getTypeOfHighestSeverity(reservationTypes).getMessageForCheck());
|
||||
|
|
|
@ -44,7 +44,6 @@ import google.registry.model.eppinput.EppInput;
|
|||
import google.registry.model.eppinput.ResourceCommand;
|
||||
import google.registry.model.eppoutput.EppResponse;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.model.registry.Registry.TldState;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import google.registry.model.tmch.ClaimsListShard;
|
||||
import google.registry.util.Clock;
|
||||
|
@ -63,7 +62,6 @@ import org.joda.time.DateTime;
|
|||
* @error {@link DomainFlowUtils.ClaimsPeriodEndedException}
|
||||
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
|
||||
* @error {@link DomainFlowUtils.TldDoesNotExistException}
|
||||
* @error {@link DomainClaimsCheckNotAllowedInSunrise}
|
||||
* @error {@link DomainClaimsCheckNotAllowedWithAllocationTokens}
|
||||
*/
|
||||
@ReportingSpec(ActivityReportField.DOMAIN_CHECK) // Claims check is a special domain check.
|
||||
|
@ -104,9 +102,6 @@ public final class DomainClaimsCheckFlow implements Flow {
|
|||
Registry registry = Registry.get(tld);
|
||||
DateTime now = clock.nowUtc();
|
||||
verifyNotInPredelegation(registry, now);
|
||||
if (registry.getTldState(now) == TldState.SUNRISE) {
|
||||
throw new DomainClaimsCheckNotAllowedInSunrise();
|
||||
}
|
||||
verifyClaimsPeriodNotEnded(registry, now);
|
||||
}
|
||||
}
|
||||
|
@ -120,13 +115,6 @@ public final class DomainClaimsCheckFlow implements Flow {
|
|||
.build();
|
||||
}
|
||||
|
||||
/** Claims checks are not allowed during sunrise. */
|
||||
static class DomainClaimsCheckNotAllowedInSunrise extends CommandUseErrorException {
|
||||
public DomainClaimsCheckNotAllowedInSunrise() {
|
||||
super("Claims checks are not allowed during sunrise");
|
||||
}
|
||||
}
|
||||
|
||||
/** Claims checks are not allowed with allocation tokens. */
|
||||
static class DomainClaimsCheckNotAllowedWithAllocationTokens extends CommandUseErrorException {
|
||||
public DomainClaimsCheckNotAllowedWithAllocationTokens() {
|
||||
|
|
|
@ -45,26 +45,21 @@ import static google.registry.model.EppResourceUtils.createDomainRepoId;
|
|||
import static google.registry.model.eppcommon.StatusValue.SERVER_HOLD;
|
||||
import static google.registry.model.eppcommon.StatusValue.SERVER_TRANSFER_PROHIBITED;
|
||||
import static google.registry.model.eppcommon.StatusValue.SERVER_UPDATE_PROHIBITED;
|
||||
import static google.registry.model.index.DomainApplicationIndex.loadActiveApplicationsByDomainName;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.model.registry.Registry.TldState.GENERAL_AVAILABILITY;
|
||||
import static google.registry.model.registry.Registry.TldState.START_DATE_SUNRISE;
|
||||
import static google.registry.model.registry.Registry.TldState.SUNRISE;
|
||||
import static google.registry.model.registry.Registry.TldState.SUNRUSH;
|
||||
import static google.registry.model.registry.label.ReservationType.NAME_COLLISION;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.leapSafeAddYears;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.net.InternetDomainName;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.dns.DnsQueue;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppException.CommandUseErrorException;
|
||||
import google.registry.flows.EppException.ParameterValuePolicyErrorException;
|
||||
import google.registry.flows.EppException.StatusProhibitsOperationException;
|
||||
import google.registry.flows.ExtensionManager;
|
||||
import google.registry.flows.FlowModule.ClientId;
|
||||
import google.registry.flows.FlowModule.Superuser;
|
||||
|
@ -81,7 +76,6 @@ import google.registry.model.billing.BillingEvent;
|
|||
import google.registry.model.billing.BillingEvent.Flag;
|
||||
import google.registry.model.billing.BillingEvent.Reason;
|
||||
import google.registry.model.billing.BillingEvent.Recurring;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
import google.registry.model.domain.DomainCommand;
|
||||
import google.registry.model.domain.DomainCommand.Create;
|
||||
import google.registry.model.domain.DomainResource;
|
||||
|
@ -130,7 +124,6 @@ import org.joda.time.Duration;
|
|||
* @error {@link google.registry.flows.EppException.UnimplementedExtensionException}
|
||||
* @error {@link google.registry.flows.ExtensionManager.UndeclaredServiceExtensionException}
|
||||
* @error {@link DomainCreateFlow.AnchorTenantCreatePeriodException}
|
||||
* @error {@link DomainCreateFlow.DomainHasOpenApplicationsException}
|
||||
* @error {@link DomainCreateFlow.MustHaveSignedMarksInCurrentPhaseException}
|
||||
* @error {@link DomainCreateFlow.NoGeneralRegistrationsInCurrentPhaseException}
|
||||
* @error {@link DomainCreateFlow.SignedMarksOnlyDuringSunriseException}
|
||||
|
@ -191,19 +184,6 @@ import org.joda.time.Duration;
|
|||
@ReportingSpec(ActivityReportField.DOMAIN_CREATE)
|
||||
public class DomainCreateFlow implements TransactionalFlow {
|
||||
|
||||
/**
|
||||
* States when the TLD is in sunrise.
|
||||
*
|
||||
* <p>Note that a TLD in SUNRUSH means sunrise is in effect, but not necessarily that the "create"
|
||||
* command is a "sunrise create". It might be a landrush create. We must make sure there's a
|
||||
* signed mark to know if the create is "sunrise" or "landrush" for verification purposes.
|
||||
*
|
||||
* <p>Note also that SUNRISE (start-date sunrise) and LANDRUSH can't "naturally" succeed in this
|
||||
* flow. They can only succeed if sent as a superuser or anchor tenant.
|
||||
*/
|
||||
private static final ImmutableSet<TldState> SUNRISE_STATES =
|
||||
Sets.immutableEnumSet(SUNRISE, SUNRUSH, START_DATE_SUNRISE);
|
||||
|
||||
/** Anchor tenant creates should always be for 2 years, since they get 2 years free. */
|
||||
private static final int ANCHOR_TENANT_CREATE_VALID_YEARS = 2;
|
||||
|
||||
|
@ -260,7 +240,7 @@ public class DomainCreateFlow implements TransactionalFlow {
|
|||
verifyNoCodeMarks(launchCreate.get());
|
||||
validateLaunchCreateNotice(launchCreate.get().getNotice(), domainLabel, isSuperuser, now);
|
||||
}
|
||||
boolean isSunriseCreate = hasSignedMarks && SUNRISE_STATES.contains(tldState);
|
||||
boolean isSunriseCreate = hasSignedMarks && tldState == START_DATE_SUNRISE;
|
||||
Optional<AllocationToken> allocationToken =
|
||||
verifyAllocationTokenIfPresent(command, registry, clientId, now);
|
||||
boolean isAnchorTenant =
|
||||
|
@ -275,6 +255,7 @@ public class DomainCreateFlow implements TransactionalFlow {
|
|||
// registering premium domains.
|
||||
if (!isSuperuser) {
|
||||
checkAllowedAccessToTld(clientId, registry.getTldStr());
|
||||
verifyIsGaOrIsSpecialCase(tldState, isAnchorTenant, hasSignedMarks);
|
||||
if (launchCreate.isPresent()) {
|
||||
verifyLaunchPhaseMatchesRegistryPhase(registry, launchCreate.get(), now);
|
||||
}
|
||||
|
@ -288,8 +269,6 @@ public class DomainCreateFlow implements TransactionalFlow {
|
|||
verifyClaimsNoticeIfAndOnlyIfNeeded(domainName, hasSignedMarks, hasClaimsNotice);
|
||||
}
|
||||
verifyPremiumNameIsNotBlocked(targetId, now, clientId);
|
||||
verifyNoOpenApplications(now);
|
||||
verifyIsGaOrIsSpecialCase(tldState, isAnchorTenant, hasSignedMarks);
|
||||
verifySignedMarkOnlyInSunrise(hasSignedMarks, tldState);
|
||||
}
|
||||
String signedMarkId = null;
|
||||
|
@ -418,7 +397,7 @@ public class DomainCreateFlow implements TransactionalFlow {
|
|||
*/
|
||||
static void verifySignedMarkOnlyInSunrise(boolean hasSignedMarks, TldState tldState)
|
||||
throws EppException {
|
||||
if (hasSignedMarks && !SUNRISE_STATES.contains(tldState)) {
|
||||
if (hasSignedMarks && tldState != START_DATE_SUNRISE) {
|
||||
throw new SignedMarksOnlyDuringSunriseException();
|
||||
}
|
||||
}
|
||||
|
@ -434,15 +413,6 @@ public class DomainCreateFlow implements TransactionalFlow {
|
|||
}
|
||||
}
|
||||
|
||||
/** Prohibit creating a domain if there is an open application for the same name. */
|
||||
private void verifyNoOpenApplications(DateTime now) throws DomainHasOpenApplicationsException {
|
||||
for (DomainApplication application : loadActiveApplicationsByDomainName(targetId, now)) {
|
||||
if (!application.getApplicationStatus().isFinalStatus()) {
|
||||
throw new DomainHasOpenApplicationsException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prohibit registrations unless QLP, General Availability or Start Date Sunrise.
|
||||
*
|
||||
|
@ -465,7 +435,7 @@ public class DomainCreateFlow implements TransactionalFlow {
|
|||
return;
|
||||
}
|
||||
|
||||
// During START_DATE_SUNRISE, only allow registration with a signed marks.
|
||||
// During START_DATE_SUNRISE, only allow registration with signed marks.
|
||||
if (START_DATE_SUNRISE.equals(tldState)) {
|
||||
if (!hasSignedMarks) {
|
||||
throw new MustHaveSignedMarksInCurrentPhaseException();
|
||||
|
@ -626,13 +596,6 @@ public class DomainCreateFlow implements TransactionalFlow {
|
|||
}
|
||||
}
|
||||
|
||||
/** There is an open application for this domain. */
|
||||
static class DomainHasOpenApplicationsException extends StatusProhibitsOperationException {
|
||||
public DomainHasOpenApplicationsException() {
|
||||
super("There is an open application for this domain");
|
||||
}
|
||||
}
|
||||
|
||||
/** The current registry phase does not allow for general registrations. */
|
||||
static class NoGeneralRegistrationsInCurrentPhaseException extends CommandUseErrorException {
|
||||
public NoGeneralRegistrationsInCurrentPhaseException() {
|
||||
|
|
|
@ -26,6 +26,8 @@ import static google.registry.model.domain.DomainResource.MAX_REGISTRATION_YEARS
|
|||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.model.registry.Registries.findTldForName;
|
||||
import static google.registry.model.registry.Registries.getTlds;
|
||||
import static google.registry.model.registry.Registry.TldState.GENERAL_AVAILABILITY;
|
||||
import static google.registry.model.registry.Registry.TldState.START_DATE_SUNRISE;
|
||||
import static google.registry.model.registry.label.ReservationType.FULLY_BLOCKED;
|
||||
import static google.registry.model.registry.label.ReservationType.NAMESERVER_RESTRICTED;
|
||||
import static google.registry.model.registry.label.ReservationType.RESERVED_FOR_ANCHOR_TENANT;
|
||||
|
@ -69,7 +71,6 @@ import google.registry.model.billing.BillingEvent.Recurring;
|
|||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.domain.DesignatedContact;
|
||||
import google.registry.model.domain.DesignatedContact.Type;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.domain.DomainCommand.Create;
|
||||
import google.registry.model.domain.DomainCommand.CreateOrUpdate;
|
||||
|
@ -132,14 +133,11 @@ import org.joda.time.Duration;
|
|||
public class DomainFlowUtils {
|
||||
|
||||
/** Map from launch phases to the allowed tld states. */
|
||||
private static final ImmutableMultimap<LaunchPhase, TldState> LAUNCH_PHASE_TO_TLD_STATES =
|
||||
new ImmutableMultimap.Builder<LaunchPhase, TldState>()
|
||||
.put(LaunchPhase.SUNRISE, TldState.SUNRISE)
|
||||
.put(LaunchPhase.SUNRUSH, TldState.SUNRUSH)
|
||||
.put(LaunchPhase.LANDRUSH, TldState.LANDRUSH)
|
||||
.put(LaunchPhase.CLAIMS, TldState.GENERAL_AVAILABILITY)
|
||||
.put(LaunchPhase.SUNRISE, TldState.START_DATE_SUNRISE)
|
||||
.put(LaunchPhase.OPEN, TldState.GENERAL_AVAILABILITY)
|
||||
private static final ImmutableMap<LaunchPhase, TldState> LAUNCH_PHASE_TO_TLD_STATES =
|
||||
new ImmutableMap.Builder<LaunchPhase, TldState>()
|
||||
.put(LaunchPhase.CLAIMS, GENERAL_AVAILABILITY)
|
||||
.put(LaunchPhase.SUNRISE, START_DATE_SUNRISE)
|
||||
.put(LaunchPhase.OPEN, GENERAL_AVAILABILITY)
|
||||
.build();
|
||||
|
||||
/** Reservation types that are only allowed in sunrise by policy. */
|
||||
|
@ -154,14 +152,6 @@ public class DomainFlowUtils {
|
|||
+ "delegated. Please visit https://www.icann.org/namecollision for more information on "
|
||||
+ "name collision.";
|
||||
|
||||
/** Non-sunrise tld states. */
|
||||
private static final ImmutableSet<TldState> DISALLOWED_TLD_STATES_FOR_APPLICATION_FLOWS =
|
||||
Sets.immutableEnumSet(
|
||||
TldState.PREDELEGATION,
|
||||
TldState.QUIET_PERIOD,
|
||||
TldState.START_DATE_SUNRISE,
|
||||
TldState.GENERAL_AVAILABILITY);
|
||||
|
||||
/** Strict validator for ascii lowercase letters, digits, and "-", allowing "." as a separator */
|
||||
private static final CharMatcher ALLOWED_CHARS =
|
||||
CharMatcher.inRange('a', 'z').or(CharMatcher.inRange('0', '9').or(CharMatcher.anyOf("-.")));
|
||||
|
@ -474,21 +464,14 @@ public class DomainFlowUtils {
|
|||
/** Verifies that a launch extension's specified phase matches the specified registry's phase. */
|
||||
static void verifyLaunchPhaseMatchesRegistryPhase(
|
||||
Registry registry, LaunchExtension launchExtension, DateTime now) throws EppException {
|
||||
if (!LAUNCH_PHASE_TO_TLD_STATES.containsEntry(
|
||||
launchExtension.getPhase(), registry.getTldState(now))) {
|
||||
if (!LAUNCH_PHASE_TO_TLD_STATES.containsKey(launchExtension.getPhase())
|
||||
|| LAUNCH_PHASE_TO_TLD_STATES.get(launchExtension.getPhase())
|
||||
!= registry.getTldState(now)) {
|
||||
// No launch operations are allowed during the quiet period or predelegation.
|
||||
throw new LaunchPhaseMismatchException();
|
||||
}
|
||||
}
|
||||
|
||||
/** Verifies that an application's domain name matches the target id (from a command). */
|
||||
static void verifyApplicationDomainMatchesTargetId(DomainApplication application, String targetId)
|
||||
throws EppException {
|
||||
if (!application.getFullyQualifiedDomainName().equals(targetId)) {
|
||||
throw new ApplicationDomainNameMismatchException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that a domain name is allowed to be delegated to the given client id. The only case
|
||||
* where it would not be allowed is if domain name is premium, and premium names are blocked by
|
||||
|
@ -601,7 +584,7 @@ public class DomainFlowUtils {
|
|||
String domainNameString = domain.toString();
|
||||
Registry registry = Registry.get(domain.parent().toString());
|
||||
int years = verifyUnitIsYears(feeRequest.getPeriod()).getValue();
|
||||
boolean isSunrise = registry.getTldState(now).equals(TldState.SUNRISE);
|
||||
boolean isSunrise = (registry.getTldState(now) == START_DATE_SUNRISE);
|
||||
|
||||
if (feeRequest.getPhase() != null || feeRequest.getSubphase() != null) {
|
||||
throw new FeeChecksDontSupportPhasesException();
|
||||
|
@ -822,9 +805,8 @@ public class DomainFlowUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Check whether a new registration period (via a create, allocate, or application create) does
|
||||
* not extend beyond a maximum number of years (e.g. {@link
|
||||
* DomainResource#MAX_REGISTRATION_YEARS}).
|
||||
* Check that a new registration period (via a create) does not extend beyond a maximum number of
|
||||
* years (e.g. {@link DomainResource#MAX_REGISTRATION_YEARS}).
|
||||
*
|
||||
* @throws ExceedsMaxRegistrationYearsException if the new registration period is too long
|
||||
*/
|
||||
|
@ -879,7 +861,7 @@ public class DomainFlowUtils {
|
|||
return ImmutableSet.copyOf(union(difference(oldDsData, toRemove), toAdd));
|
||||
}
|
||||
|
||||
/** If a domain or application has "clientUpdateProhibited" set, updates must clear it or fail. */
|
||||
/** If a domain "clientUpdateProhibited" set, updates must clear it or fail. */
|
||||
static void verifyClientUpdateNotProhibited(Update command, DomainBase existingResource)
|
||||
throws ResourceHasClientUpdateProhibitedException {
|
||||
if (existingResource.getStatusValues().contains(StatusValue.CLIENT_UPDATE_PROHIBITED)
|
||||
|
@ -905,14 +887,6 @@ public class DomainFlowUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/** Check that the registry phase is not incompatible with launch extension flows. */
|
||||
static void verifyRegistryStateAllowsApplicationFlows(Registry registry, DateTime now)
|
||||
throws BadCommandForRegistryPhaseException {
|
||||
if (DISALLOWED_TLD_STATES_FOR_APPLICATION_FLOWS.contains(registry.getTldState(now))) {
|
||||
throw new BadCommandForRegistryPhaseException();
|
||||
}
|
||||
}
|
||||
|
||||
/** Check that the registry phase is not predelegation, during which some flows are forbidden. */
|
||||
public static void verifyNotInPredelegation(Registry registry, DateTime now)
|
||||
throws BadCommandForRegistryPhaseException {
|
||||
|
@ -921,7 +895,7 @@ public class DomainFlowUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/** Validate the contacts and nameservers specified in a domain or application create command. */
|
||||
/** Validate the contacts and nameservers specified in a domain create command. */
|
||||
static void validateCreateCommandContactsAndNameservers(
|
||||
Create command, Registry registry, InternetDomainName domainName) throws EppException {
|
||||
verifyNotInPendingDelete(
|
||||
|
@ -993,7 +967,7 @@ public class DomainFlowUtils {
|
|||
|
||||
/**
|
||||
* Check that if there's a claims notice it's on the claims list, and that if there's not one it's
|
||||
* not on the claims list and is a sunrise application.
|
||||
* not on the claims list.
|
||||
*/
|
||||
static void verifyClaimsNoticeIfAndOnlyIfNeeded(
|
||||
InternetDomainName domainName, boolean hasSignedMarks, boolean hasClaimsNotice)
|
||||
|
@ -1016,7 +990,7 @@ public class DomainFlowUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/** Create a response extension listing the fees on a domain or application create. */
|
||||
/** Create a response extension listing the fees on a domain create. */
|
||||
static FeeTransformResponseExtension createFeeCreateResponse(
|
||||
FeeTransformCommandExtension feeCreate, FeesAndCredits feesAndCredits) {
|
||||
return feeCreate
|
||||
|
@ -1185,13 +1159,6 @@ public class DomainFlowUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/** Application referenced does not match specified domain name. */
|
||||
static class ApplicationDomainNameMismatchException extends ParameterValuePolicyErrorException {
|
||||
public ApplicationDomainNameMismatchException() {
|
||||
super("Application referenced does not match specified domain name");
|
||||
}
|
||||
}
|
||||
|
||||
/** Too many DS records set on a domain. */
|
||||
static class TooManyDsRecordsException extends ParameterValuePolicyErrorException {
|
||||
public TooManyDsRecordsException(String message) {
|
||||
|
|
|
@ -22,13 +22,11 @@ import com.google.common.net.InternetDomainName;
|
|||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.FlowScope;
|
||||
import google.registry.flows.custom.DomainPricingCustomLogic;
|
||||
import google.registry.flows.custom.DomainPricingCustomLogic.ApplicationUpdatePriceParameters;
|
||||
import google.registry.flows.custom.DomainPricingCustomLogic.CreatePriceParameters;
|
||||
import google.registry.flows.custom.DomainPricingCustomLogic.RenewPriceParameters;
|
||||
import google.registry.flows.custom.DomainPricingCustomLogic.RestorePriceParameters;
|
||||
import google.registry.flows.custom.DomainPricingCustomLogic.TransferPriceParameters;
|
||||
import google.registry.flows.custom.DomainPricingCustomLogic.UpdatePriceParameters;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
import google.registry.model.domain.fee.BaseFee;
|
||||
import google.registry.model.domain.fee.BaseFee.FeeType;
|
||||
import google.registry.model.domain.fee.Fee;
|
||||
|
@ -162,25 +160,6 @@ public final class DomainPricingLogic {
|
|||
.build());
|
||||
}
|
||||
|
||||
/** Returns a new domain application update price for the pricer. */
|
||||
@SuppressWarnings("unused")
|
||||
public FeesAndCredits getApplicationUpdatePrice(
|
||||
Registry registry, DomainApplication application, DateTime date) throws EppException {
|
||||
BaseFee feeOrCredit =
|
||||
Fee.create(Money.zero(registry.getCurrency()).getAmount(), FeeType.UPDATE);
|
||||
return customLogic.customizeApplicationUpdatePrice(
|
||||
ApplicationUpdatePriceParameters.newBuilder()
|
||||
.setFeesAndCredits(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(registry.getCurrency())
|
||||
.setFeesAndCredits(feeOrCredit)
|
||||
.build())
|
||||
.setRegistry(registry)
|
||||
.setDomainApplication(application)
|
||||
.setAsOfDate(date)
|
||||
.build());
|
||||
}
|
||||
|
||||
/** Returns the fee class for a given domain and date. */
|
||||
public Optional<String> getFeeClass(String domainName, DateTime date) {
|
||||
return getDomainFeeClass(domainName, date);
|
||||
|
|
|
@ -42,7 +42,6 @@ import static google.registry.flows.domain.DomainFlowUtils.verifyClientUpdateNot
|
|||
import static google.registry.flows.domain.DomainFlowUtils.verifyNotInPendingDelete;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.util.CollectionUtils.nullToEmpty;
|
||||
import static google.registry.util.DateTimeUtils.earliestOf;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.net.InternetDomainName;
|
||||
|
@ -67,10 +66,8 @@ import google.registry.model.domain.DomainCommand.Update;
|
|||
import google.registry.model.domain.DomainCommand.Update.AddRemove;
|
||||
import google.registry.model.domain.DomainCommand.Update.Change;
|
||||
import google.registry.model.domain.DomainResource;
|
||||
import google.registry.model.domain.GracePeriod;
|
||||
import google.registry.model.domain.fee.FeeUpdateCommandExtension;
|
||||
import google.registry.model.domain.metadata.MetadataExtension;
|
||||
import google.registry.model.domain.rgp.GracePeriodStatus;
|
||||
import google.registry.model.domain.secdns.SecDnsUpdateExtension;
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
|
@ -94,12 +91,6 @@ import org.joda.time.DateTime;
|
|||
* superuser. As such, adding or removing these statuses incurs a billing event. There will be only
|
||||
* one charge per update, even if several such statuses are updated at once.
|
||||
*
|
||||
* <p>If a domain was created during the sunrise or landrush phases of a TLD, is still within the
|
||||
* sunrushAddGracePeriod and has not yet been delegated in DNS, then it will not yet have been
|
||||
* billed for. Any update that causes the name to be delegated (such * as adding nameservers or
|
||||
* removing a hold status) will cause the domain to convert to a normal create and be billed for
|
||||
* accordingly.
|
||||
*
|
||||
* @error {@link google.registry.flows.EppException.UnimplementedExtensionException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
|
||||
|
@ -177,16 +168,6 @@ public final class DomainUpdateFlow implements TransactionalFlow {
|
|||
AfterValidationParameters.newBuilder().setExistingDomain(existingDomain).build());
|
||||
HistoryEntry historyEntry = buildHistoryEntry(existingDomain, now);
|
||||
DomainResource newDomain = performUpdate(command, existingDomain, now);
|
||||
// If the new domain is in the sunrush add grace period and is now publishable to DNS because we
|
||||
// have added nameserver or removed holds, we have to convert it to a standard add grace period.
|
||||
if (newDomain.shouldPublishToDns()) {
|
||||
for (GracePeriod gracePeriod : newDomain.getGracePeriods()) {
|
||||
if (gracePeriod.isSunrushAddGracePeriod()) {
|
||||
newDomain = convertSunrushAddToAdd(newDomain, gracePeriod, historyEntry, now);
|
||||
break; // There can only be one sunrush add grace period.
|
||||
}
|
||||
}
|
||||
}
|
||||
validateNewState(newDomain);
|
||||
dnsQueue.addDomainRefreshTask(targetId);
|
||||
ImmutableSet.Builder<ImmutableObject> entitiesToSave = new ImmutableSet.Builder<>();
|
||||
|
@ -289,50 +270,6 @@ public final class DomainUpdateFlow implements TransactionalFlow {
|
|||
return domainBuilder.build();
|
||||
}
|
||||
|
||||
private DomainResource convertSunrushAddToAdd(
|
||||
DomainResource newDomain, GracePeriod gracePeriod, HistoryEntry historyEntry, DateTime now) {
|
||||
// Cancel the billing event for the sunrush add and replace it with a new billing event.
|
||||
BillingEvent.Cancellation billingEventCancellation =
|
||||
BillingEvent.Cancellation.forGracePeriod(gracePeriod, historyEntry, targetId);
|
||||
BillingEvent.OneTime billingEvent =
|
||||
createBillingEventForSunrushConversion(newDomain, historyEntry, gracePeriod, now);
|
||||
ofy().save().entities(billingEvent, billingEventCancellation);
|
||||
// Modify the grace periods on the domain.
|
||||
return newDomain.asBuilder()
|
||||
.removeGracePeriod(gracePeriod)
|
||||
.addGracePeriod(GracePeriod.forBillingEvent(GracePeriodStatus.ADD, billingEvent))
|
||||
.build();
|
||||
}
|
||||
|
||||
private BillingEvent.OneTime createBillingEventForSunrushConversion(
|
||||
DomainResource existingDomain,
|
||||
HistoryEntry historyEntry,
|
||||
GracePeriod sunrushAddGracePeriod,
|
||||
DateTime now) {
|
||||
// Compute the expiration time of the add grace period. We will not allow it to be after the
|
||||
// sunrush add grace period expiration time (i.e. you can't get extra add grace period by
|
||||
// setting a nameserver).
|
||||
DateTime addGracePeriodExpirationTime = earliestOf(
|
||||
now.plus(Registry.get(existingDomain.getTld()).getAddGracePeriodLength()),
|
||||
sunrushAddGracePeriod.getExpirationTime());
|
||||
// Create a new billing event for the add grace period. Note that we do this even if it would
|
||||
// occur at the same time as the sunrush add grace period, as the event time will differ
|
||||
// between them.
|
||||
BillingEvent.OneTime originalAddEvent =
|
||||
ofy().load().key(sunrushAddGracePeriod.getOneTimeBillingEvent()).now();
|
||||
return new BillingEvent.OneTime.Builder()
|
||||
.setReason(Reason.CREATE)
|
||||
.setTargetId(targetId)
|
||||
.setFlags(originalAddEvent.getFlags())
|
||||
.setClientId(sunrushAddGracePeriod.getClientId())
|
||||
.setCost(originalAddEvent.getCost())
|
||||
.setPeriodYears(originalAddEvent.getPeriodYears())
|
||||
.setEventTime(now)
|
||||
.setBillingTime(addGracePeriodExpirationTime)
|
||||
.setParent(historyEntry)
|
||||
.build();
|
||||
}
|
||||
|
||||
private void validateRegistrantIsntBeingRemoved(Change change) throws EppException {
|
||||
if (change.getRegistrantContactId() != null && change.getRegistrantContactId().isEmpty()) {
|
||||
throw new MissingRegistrantException();
|
||||
|
|
|
@ -14,11 +14,8 @@
|
|||
|
||||
package google.registry.flows.picker;
|
||||
|
||||
import static google.registry.model.domain.launch.LaunchCreateExtension.CreateType.APPLICATION;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableTable;
|
||||
import com.google.common.collect.Table;
|
||||
import google.registry.flows.EppException;
|
||||
|
@ -35,11 +32,6 @@ import google.registry.flows.contact.ContactTransferQueryFlow;
|
|||
import google.registry.flows.contact.ContactTransferRejectFlow;
|
||||
import google.registry.flows.contact.ContactTransferRequestFlow;
|
||||
import google.registry.flows.contact.ContactUpdateFlow;
|
||||
import google.registry.flows.domain.DomainAllocateFlow;
|
||||
import google.registry.flows.domain.DomainApplicationCreateFlow;
|
||||
import google.registry.flows.domain.DomainApplicationDeleteFlow;
|
||||
import google.registry.flows.domain.DomainApplicationInfoFlow;
|
||||
import google.registry.flows.domain.DomainApplicationUpdateFlow;
|
||||
import google.registry.flows.domain.DomainCheckFlow;
|
||||
import google.registry.flows.domain.DomainClaimsCheckFlow;
|
||||
import google.registry.flows.domain.DomainCreateFlow;
|
||||
|
@ -65,11 +57,8 @@ import google.registry.flows.session.LoginFlow;
|
|||
import google.registry.flows.session.LogoutFlow;
|
||||
import google.registry.model.contact.ContactCommand;
|
||||
import google.registry.model.domain.DomainCommand;
|
||||
import google.registry.model.domain.allocate.AllocateCreateExtension;
|
||||
import google.registry.model.domain.launch.ApplicationIdTargetExtension;
|
||||
import google.registry.model.domain.launch.LaunchCheckExtension;
|
||||
import google.registry.model.domain.launch.LaunchCheckExtension.CheckType;
|
||||
import google.registry.model.domain.launch.LaunchCreateExtension;
|
||||
import google.registry.model.domain.launch.LaunchPhase;
|
||||
import google.registry.model.domain.rgp.RestoreCommand.RestoreOp;
|
||||
import google.registry.model.domain.rgp.RgpUpdateExtension;
|
||||
|
@ -229,74 +218,6 @@ public class FlowPicker {
|
|||
return resourceCommand == null ? null : resourceCrudFlows.get(resourceCommand.getClass());
|
||||
}};
|
||||
|
||||
/** The domain allocate flow has a specific extension. */
|
||||
private static final FlowProvider ALLOCATE_FLOW_PROVIDER =
|
||||
new FlowProvider() {
|
||||
@Override
|
||||
Class<? extends Flow> get(
|
||||
EppInput eppInput, InnerCommand innerCommand, ResourceCommand resourceCommand) {
|
||||
return (resourceCommand instanceof DomainCommand.Create
|
||||
&& eppInput.getSingleExtension(AllocateCreateExtension.class).isPresent())
|
||||
? DomainAllocateFlow.class
|
||||
: null;
|
||||
}
|
||||
};
|
||||
|
||||
private static final ImmutableSet<LaunchPhase> LAUNCH_PHASES_DEFAULTING_TO_APPLICATION =
|
||||
ImmutableSet.of(LaunchPhase.SUNRUSH, LaunchPhase.LANDRUSH);
|
||||
|
||||
/**
|
||||
* Application CRUD flows have an extension and are keyed on the type of their {@link
|
||||
* ResourceCommand}.
|
||||
*/
|
||||
private static final FlowProvider APPLICATION_CRUD_FLOW_PROVIDER =
|
||||
new FlowProvider() {
|
||||
|
||||
private final Map<Class<? extends ResourceCommand>, Class<? extends Flow>>
|
||||
applicationFlows =
|
||||
ImmutableMap.of(
|
||||
DomainCommand.Create.class, DomainApplicationCreateFlow.class,
|
||||
DomainCommand.Delete.class, DomainApplicationDeleteFlow.class,
|
||||
DomainCommand.Info.class, DomainApplicationInfoFlow.class,
|
||||
DomainCommand.Update.class, DomainApplicationUpdateFlow.class);
|
||||
|
||||
@Override
|
||||
Class<? extends Flow> get(
|
||||
EppInput eppInput, InnerCommand innerCommand, ResourceCommand resourceCommand) {
|
||||
if (eppInput.getSingleExtension(ApplicationIdTargetExtension.class).isPresent()) {
|
||||
return applicationFlows.get(resourceCommand.getClass());
|
||||
}
|
||||
Optional<LaunchCreateExtension> createExtension =
|
||||
eppInput.getSingleExtension(LaunchCreateExtension.class);
|
||||
// Return a flow if the type is APPLICATION. If the type is REGISTRATION, return null.
|
||||
if (createExtension.isPresent()) {
|
||||
LaunchPhase launchPhase = createExtension.get().getPhase();
|
||||
// <launch:create> has an optional type argument, that can take either "application" or
|
||||
// "registration".
|
||||
// https://tools.ietf.org/html/rfc8334#section-3.3.1
|
||||
// We get that type via createExtension.get().getCreateType()
|
||||
// If it isn't given, the function returns null.
|
||||
// In that case, we need to decide based on the TLD. For now we can't do that - so we
|
||||
// TEMPORARILY decide as follows:
|
||||
// landrush and sunrush phases will default to APPLICATION, because there's no possible
|
||||
// registration for it.
|
||||
// sunrise defaults to REGISTRATION because we're currenly launching start-date sunrise
|
||||
// that uses direct registration.
|
||||
//
|
||||
// TODO(b/76095570): if createExtension.get().getCreateType() isn't explicitly given,
|
||||
// we need to set it according to the TldState (which means we need to know the TLD and
|
||||
// load the Registry - which will probably result in a big refactoring since we can use
|
||||
// TldState information to pick the flow)
|
||||
if (APPLICATION.equals(createExtension.get().getCreateType())
|
||||
|| (createExtension.get().getCreateType() == null
|
||||
&& LAUNCH_PHASES_DEFAULTING_TO_APPLICATION.contains(launchPhase))) {
|
||||
return applicationFlows.get(resourceCommand.getClass());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/** Transfer flows have an {@link InnerCommand} of type {@link Transfer}. */
|
||||
private static final FlowProvider TRANSFER_FLOW_PROVIDER = new FlowProvider() {
|
||||
private final Table<Class<?>, TransferOp, Class<? extends Flow>> transferFlows = ImmutableTable
|
||||
|
@ -327,8 +248,6 @@ public class FlowPicker {
|
|||
SESSION_FLOW_PROVIDER,
|
||||
POLL_FLOW_PROVIDER,
|
||||
DOMAIN_RESTORE_FLOW_PROVIDER,
|
||||
ALLOCATE_FLOW_PROVIDER,
|
||||
APPLICATION_CRUD_FLOW_PROVIDER,
|
||||
DOMAIN_CHECK_FLOW_PROVIDER,
|
||||
RESOURCE_CRUD_FLOW_PROVIDER,
|
||||
TRANSFER_FLOW_PROVIDER);
|
||||
|
|
|
@ -76,7 +76,6 @@ public class PollRequestFlow implements Flow {
|
|||
.setMessageId(makePollMessageExternalId(pollMessage))
|
||||
.build())
|
||||
.setMultipleResData(pollMessage.getResponseData())
|
||||
.setExtensions(pollMessage.getResponseExtensions())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -40,8 +40,7 @@ abstract class EppResourceBaseReader<T> extends RetryingInputReader<EppResourceI
|
|||
* The resource kinds to filter for.
|
||||
*
|
||||
* <p>This can be empty, or any of {"ContactResource", "HostResource", "DomainBase"}. It will
|
||||
* never contain "EppResource", "DomainResource" or "DomainApplication" since these aren't
|
||||
* actual kinds in Datastore.
|
||||
* never contain "EppResource" or "DomainResource" since these aren't actual kinds in Datastore.
|
||||
*/
|
||||
private final ImmutableSet<String> filterKinds;
|
||||
|
||||
|
|
|
@ -20,12 +20,10 @@ import google.registry.model.common.Cursor;
|
|||
import google.registry.model.common.EntityGroupRoot;
|
||||
import google.registry.model.common.GaeUserIdConverter;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.domain.DomainResource;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.host.HostResource;
|
||||
import google.registry.model.index.DomainApplicationIndex;
|
||||
import google.registry.model.index.EppResourceIndex;
|
||||
import google.registry.model.index.EppResourceIndexBucket;
|
||||
import google.registry.model.index.ForeignKeyIndex;
|
||||
|
@ -74,8 +72,6 @@ public final class EntityClasses {
|
|||
CommitLogMutation.class,
|
||||
ContactResource.class,
|
||||
Cursor.class,
|
||||
DomainApplication.class,
|
||||
DomainApplicationIndex.class,
|
||||
DomainBase.class,
|
||||
DomainResource.class,
|
||||
EntityGroupRoot.class,
|
||||
|
|
|
@ -51,7 +51,7 @@ import java.util.Set;
|
|||
import java.util.concurrent.ExecutionException;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** An EPP entity object (i.e. a domain, application, contact, or host). */
|
||||
/** An EPP entity object (i.e. a domain, contact, or host). */
|
||||
public abstract class EppResource extends BackupGroupRoot implements Buildable {
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,7 +33,6 @@ import google.registry.model.EppResource.BuilderWithTransferData;
|
|||
import google.registry.model.EppResource.ForeignKeyedEppResource;
|
||||
import google.registry.model.EppResource.ResourceWithTransferData;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.index.ForeignKeyIndex;
|
||||
|
@ -158,22 +157,6 @@ public final class EppResourceUtils {
|
|||
resource, latestOf(now, resource.getUpdateAutoTimestamp().getTimestamp())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the domain application with the given application id if it exists, or absent if it does
|
||||
* not or is soft-deleted as of the given time.
|
||||
*/
|
||||
public static Optional<DomainApplication> loadDomainApplication(
|
||||
String applicationId, DateTime now) {
|
||||
DomainApplication application =
|
||||
ofy().load().key(Key.create(DomainApplication.class, applicationId)).now();
|
||||
if (application == null || isAtOrAfter(now, application.getDeletionTime())) {
|
||||
return Optional.empty();
|
||||
}
|
||||
// Applications don't have any speculative changes that become effective later, so no need to
|
||||
// clone forward in time.
|
||||
return Optional.of(application);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks multiple {@link EppResource} objects from Datastore by unique ids.
|
||||
*
|
||||
|
|
|
@ -100,7 +100,6 @@ public final class OteAccountBuilder {
|
|||
|
||||
private final ImmutableMap<String, String> clientIdToTld;
|
||||
private final Registry sunriseTld;
|
||||
private final Registry landrushTld;
|
||||
private final Registry gaTld;
|
||||
private final Registry eapTld;
|
||||
private final ImmutableList.Builder<RegistrarContact> contactsBuilder =
|
||||
|
@ -117,8 +116,6 @@ public final class OteAccountBuilder {
|
|||
sunriseTld =
|
||||
createTld(
|
||||
baseClientId + "-sunrise", TldState.START_DATE_SUNRISE, null, null, null, false, 0);
|
||||
landrushTld =
|
||||
createTld(baseClientId + "-landrush", TldState.LANDRUSH, null, null, null, false, 1);
|
||||
gaTld =
|
||||
createTld(
|
||||
baseClientId + "-ga",
|
||||
|
@ -260,7 +257,7 @@ public final class OteAccountBuilder {
|
|||
private void saveAllEntities() {
|
||||
ofy().assertInTransaction();
|
||||
|
||||
ImmutableList<Registry> registries = ImmutableList.of(sunriseTld, landrushTld, gaTld, eapTld);
|
||||
ImmutableList<Registry> registries = ImmutableList.of(sunriseTld, gaTld, eapTld);
|
||||
ImmutableList<RegistrarContact> contacts = contactsBuilder.build();
|
||||
|
||||
if (!replaceExisting) {
|
||||
|
@ -368,7 +365,7 @@ public final class OteAccountBuilder {
|
|||
baseClientId);
|
||||
return new ImmutableMap.Builder<String, String>()
|
||||
.put(baseClientId + "-1", baseClientId + "-sunrise")
|
||||
.put(baseClientId + "-2", baseClientId + "-landrush")
|
||||
// The -2 registrar no longer exists because landrush no longer exists.
|
||||
.put(baseClientId + "-3", baseClientId + "-ga")
|
||||
.put(baseClientId + "-4", baseClientId + "-ga")
|
||||
.put(baseClientId + "-5", baseClientId + "-eap")
|
||||
|
|
|
@ -102,12 +102,6 @@ public class OteStats {
|
|||
CONTACT_TRANSFER_REJECTS(0, equalTo(Type.CONTACT_TRANSFER_REJECT)),
|
||||
CONTACT_TRANSFER_REQUESTS(0, equalTo(Type.CONTACT_TRANSFER_REQUEST)),
|
||||
CONTACT_UPDATES(0, equalTo(Type.CONTACT_UPDATE)),
|
||||
DOMAIN_APPLICATION_CREATES(0, equalTo(Type.DOMAIN_APPLICATION_CREATE)),
|
||||
DOMAIN_APPLICATION_CREATES_LANDRUSH(
|
||||
0, equalTo(Type.DOMAIN_APPLICATION_CREATE), IS_SUNRISE.negate()),
|
||||
DOMAIN_APPLICATION_CREATES_SUNRISE(0, equalTo(Type.DOMAIN_APPLICATION_CREATE), IS_SUNRISE),
|
||||
DOMAIN_APPLICATION_DELETES(0, equalTo(Type.DOMAIN_APPLICATION_DELETE)),
|
||||
DOMAIN_APPLICATION_UPDATES(0, equalTo(Type.DOMAIN_APPLICATION_UPDATE)),
|
||||
DOMAIN_AUTORENEWS(0, equalTo(Type.DOMAIN_AUTORENEW)),
|
||||
DOMAIN_CREATES(0, equalTo(Type.DOMAIN_CREATE)),
|
||||
DOMAIN_CREATES_ASCII(1, equalTo(Type.DOMAIN_CREATE), IS_IDN.negate()),
|
||||
|
|
|
@ -70,6 +70,9 @@ public abstract class BillingEvent extends ImmutableObject
|
|||
ALLOCATION,
|
||||
ANCHOR_TENANT,
|
||||
AUTO_RENEW,
|
||||
/**
|
||||
* Landrush billing events are historical only and are no longer created.
|
||||
*/
|
||||
LANDRUSH,
|
||||
/**
|
||||
* This flag is used on create {@link OneTime} billing events for domains that were reserved.
|
||||
|
|
|
@ -1,151 +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.model.domain;
|
||||
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.googlecode.objectify.annotation.EntitySubclass;
|
||||
import google.registry.model.annotations.ExternalMessagingName;
|
||||
import google.registry.model.domain.launch.ApplicationStatus;
|
||||
import google.registry.model.domain.launch.LaunchPhase;
|
||||
import google.registry.model.eppcommon.Trid;
|
||||
import google.registry.model.smd.EncodedSignedMark;
|
||||
import java.util.List;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** An application to create a domain. */
|
||||
@EntitySubclass(index = true)
|
||||
@ExternalMessagingName("application")
|
||||
public class DomainApplication extends DomainBase {
|
||||
|
||||
/**
|
||||
* The transaction id of the EPP command that created this application. This is saved off so that
|
||||
* we can generate the poll message communicating the application result once it is rejected or
|
||||
* allocated.
|
||||
*
|
||||
* <p>This field may be null for applications that were created before the field was added.
|
||||
*/
|
||||
Trid creationTrid;
|
||||
|
||||
/**
|
||||
* The phase which this application is registered for. We store this only so we can return it back
|
||||
* to the user on info commands.
|
||||
*/
|
||||
LaunchPhase phase;
|
||||
|
||||
/** The requested registration period. */
|
||||
Period period;
|
||||
|
||||
/** The current status of this application. */
|
||||
ApplicationStatus applicationStatus;
|
||||
|
||||
/** The encoded signed marks which were asserted when this application was created. */
|
||||
List<EncodedSignedMark> encodedSignedMarks;
|
||||
|
||||
/** The amount paid at auction for the right to register the domain. Used only for reporting. */
|
||||
Money auctionPrice;
|
||||
|
||||
@Override
|
||||
public String getFullyQualifiedDomainName() {
|
||||
return fullyQualifiedDomainName;
|
||||
}
|
||||
|
||||
public Trid getCreationTrid() {
|
||||
return creationTrid;
|
||||
}
|
||||
|
||||
public LaunchPhase getPhase() {
|
||||
return phase;
|
||||
}
|
||||
|
||||
public Period getPeriod() {
|
||||
return period;
|
||||
}
|
||||
|
||||
public ApplicationStatus getApplicationStatus() {
|
||||
return applicationStatus;
|
||||
}
|
||||
|
||||
public ImmutableList<EncodedSignedMark> getEncodedSignedMarks() {
|
||||
return nullToEmptyImmutableCopy(encodedSignedMarks);
|
||||
}
|
||||
|
||||
public Money getAuctionPrice() {
|
||||
return auctionPrice;
|
||||
}
|
||||
|
||||
/**
|
||||
* The application id is the repoId.
|
||||
*/
|
||||
@Override
|
||||
public String getForeignKey() {
|
||||
return getRepoId();
|
||||
}
|
||||
|
||||
/** This is a no-op and should never be called on an application explicitly. */
|
||||
@Deprecated
|
||||
@Override
|
||||
public DomainApplication cloneProjectedAtTime(DateTime now) {
|
||||
// Applications have no grace periods and can't be transferred, so there is nothing to project.
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder asBuilder() {
|
||||
return new Builder(clone(this));
|
||||
}
|
||||
|
||||
/** A builder for constructing {@link DomainApplication}, since it is immutable. */
|
||||
public static class Builder extends DomainBase.Builder<DomainApplication, Builder> {
|
||||
|
||||
public Builder() {}
|
||||
|
||||
private Builder(DomainApplication instance) {
|
||||
super(instance);
|
||||
}
|
||||
|
||||
public Builder setCreationTrid(Trid creationTrid) {
|
||||
getInstance().creationTrid = creationTrid;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setPhase(LaunchPhase phase) {
|
||||
getInstance().phase = phase;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setPeriod(Period period) {
|
||||
getInstance().period = period;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setApplicationStatus(ApplicationStatus applicationStatus) {
|
||||
getInstance().applicationStatus = applicationStatus;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setEncodedSignedMarks(ImmutableList<EncodedSignedMark> encodedSignedMarks) {
|
||||
getInstance().encodedSignedMarks = encodedSignedMarks;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAuctionPrice(Money auctionPrice) {
|
||||
getInstance().auctionPrice = auctionPrice;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -50,7 +50,8 @@ import java.util.Objects;
|
|||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/** Shared base class for {@link DomainResource} and {@link DomainApplication}. */
|
||||
/** Base class for {@link DomainResource}. */
|
||||
// TODO(b/121028829): Squash DomainResource into this.
|
||||
@ReportedOn
|
||||
@Entity
|
||||
public abstract class DomainBase extends EppResource {
|
||||
|
|
|
@ -106,26 +106,13 @@ public class DomainResource extends DomainBase
|
|||
Set<GracePeriod> gracePeriods;
|
||||
|
||||
/**
|
||||
* The id of the signed mark that was used to create the sunrise application for this domain.
|
||||
* Will only be populated for domains allocated from a sunrise application.
|
||||
* The id of the signed mark that was used to create this domain in sunrise.
|
||||
*
|
||||
* <p>Will only be populated for domains created in sunrise.
|
||||
*/
|
||||
@IgnoreSave(IfNull.class)
|
||||
String smdId;
|
||||
|
||||
/**
|
||||
* The time that the application used to allocate this domain was created. Will only be populated
|
||||
* for domains allocated from an application.
|
||||
*/
|
||||
@IgnoreSave(IfNull.class)
|
||||
DateTime applicationTime;
|
||||
|
||||
/**
|
||||
* A key to the application used to allocate this domain. Will only be populated for domains
|
||||
* allocated from an application.
|
||||
*/
|
||||
@IgnoreSave(IfNull.class)
|
||||
Key<DomainApplication> application;
|
||||
|
||||
/** Data about any pending or past transfers on this domain. */
|
||||
TransferData transferData;
|
||||
|
||||
|
@ -164,14 +151,6 @@ public class DomainResource extends DomainBase
|
|||
return smdId;
|
||||
}
|
||||
|
||||
public DateTime getApplicationTime() {
|
||||
return applicationTime;
|
||||
}
|
||||
|
||||
public Key<DomainApplication> getApplication() {
|
||||
return application;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final TransferData getTransferData() {
|
||||
return Optional.ofNullable(transferData).orElse(TransferData.EMPTY);
|
||||
|
@ -426,16 +405,6 @@ public class DomainResource extends DomainBase
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder setApplicationTime(DateTime applicationTime) {
|
||||
getInstance().applicationTime = applicationTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setApplication(Key<DomainApplication> application) {
|
||||
getInstance().application = application;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setGracePeriods(ImmutableSet<GracePeriod> gracePeriods) {
|
||||
getInstance().gracePeriods = gracePeriods;
|
||||
return this;
|
||||
|
|
|
@ -59,12 +59,7 @@ public class GracePeriod extends ImmutableObject {
|
|||
Key<BillingEvent.Recurring> billingEventRecurring = null;
|
||||
|
||||
public GracePeriodStatus getType() {
|
||||
// NB: We implicitly convert SUNRUSH_ADD to ADD, since they should be functionally equivalent.
|
||||
return type == GracePeriodStatus.SUNRUSH_ADD ? GracePeriodStatus.ADD : type;
|
||||
}
|
||||
|
||||
public boolean isSunrushAddGracePeriod() {
|
||||
return type == GracePeriodStatus.SUNRUSH_ADD;
|
||||
return type;
|
||||
}
|
||||
|
||||
public DateTime getExpirationTime() {
|
||||
|
|
|
@ -1,83 +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.model.domain.allocate;
|
||||
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.domain.launch.LaunchNotice;
|
||||
import google.registry.model.eppinput.EppInput.CommandExtension;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* An XML data object that represents an allocate extension that will be present on EPP commands to
|
||||
* allocate a domain from an application.
|
||||
*
|
||||
* <p>This object holds XML data which JAXB will unmarshal from an EPP domain create command
|
||||
* extension. The XML will have the following enclosing structure:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <epp>
|
||||
* <command>
|
||||
* <create>
|
||||
* <!-- domain create XML data -->
|
||||
* </create>
|
||||
* <extension>
|
||||
* <allocate:create>
|
||||
* <!-- allocate create XML payload data -->
|
||||
* </allocate:create>
|
||||
* </extension>
|
||||
* </command>
|
||||
* </epp>
|
||||
* } </pre>
|
||||
*
|
||||
* @see CommandExtension
|
||||
*/
|
||||
@XmlRootElement(name = "create")
|
||||
public class AllocateCreateExtension extends ImmutableObject implements CommandExtension {
|
||||
|
||||
/** Holds the ROID of the application that was used to allocate this domain. */
|
||||
String applicationRoid;
|
||||
|
||||
/** The time that the application was created. */
|
||||
DateTime applicationTime;
|
||||
|
||||
/**
|
||||
* Signed mark identifier for this create. Only present when allocating a domain from a sunrise
|
||||
* application.
|
||||
*/
|
||||
String smdId;
|
||||
|
||||
/**
|
||||
* The claims notice for this create. Only present when allocating a domain from a landrush
|
||||
* application that matches a pre-registered mark in the TMCH.
|
||||
*/
|
||||
LaunchNotice notice;
|
||||
|
||||
public String getApplicationRoid() {
|
||||
return applicationRoid;
|
||||
}
|
||||
|
||||
public DateTime getApplicationTime() {
|
||||
return applicationTime;
|
||||
}
|
||||
|
||||
public String getSmdId() {
|
||||
return smdId;
|
||||
}
|
||||
|
||||
public LaunchNotice getNotice() {
|
||||
return notice;
|
||||
}
|
||||
}
|
|
@ -1,30 +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.
|
||||
|
||||
@XmlSchema(
|
||||
namespace = "urn:google:params:xml:ns:allocate-1.0",
|
||||
xmlns = @XmlNs(prefix = "allocate", namespaceURI = "urn:google:params:xml:ns:allocate-1.0"),
|
||||
elementFormDefault = XmlNsForm.QUALIFIED)
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlJavaTypeAdapter(UtcDateTimeAdapter.class)
|
||||
package google.registry.model.domain.allocate;
|
||||
|
||||
import google.registry.xml.UtcDateTimeAdapter;
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlNs;
|
||||
import javax.xml.bind.annotation.XmlNsForm;
|
||||
import javax.xml.bind.annotation.XmlSchema;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
|
@ -1,23 +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.model.domain.launch;
|
||||
|
||||
import google.registry.model.eppinput.EppInput.CommandExtension;
|
||||
|
||||
/** Marker interface for EPP extensions which override the EPP notion of id with their own. */
|
||||
public interface ApplicationIdTargetExtension extends CommandExtension {
|
||||
/** Get the application id to use as the resource id for commands using this extension. */
|
||||
String getApplicationId();
|
||||
}
|
|
@ -1,58 +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.model.domain.launch;
|
||||
|
||||
import static com.google.common.base.CaseFormat.LOWER_CAMEL;
|
||||
import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
|
||||
|
||||
import google.registry.model.translators.EnumToAttributeAdapter;
|
||||
import google.registry.model.translators.EnumToAttributeAdapter.EppEnum;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
/**
|
||||
* Represents the EPP application status.
|
||||
*
|
||||
* <p>These values are never read from a command and only used in responses, so, we don't need to
|
||||
* model anything we don't output. We don't model the CUSTOM status because we don't use it. This
|
||||
* allows us to also avoid modeling the "name" attribute which is only used with CUSTOM. We don't
|
||||
* model the "lang" attribute because we only support English and that's the default.
|
||||
*
|
||||
* <p>Given all of this, we can use {@link EnumToAttributeAdapter} to make this code very simple.
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/draft-tan-epp-launchphase-11#section-2.3">
|
||||
* Launch Phase Mapping for EPP - Status Values</a>
|
||||
*/
|
||||
@XmlJavaTypeAdapter(EnumToAttributeAdapter.class)
|
||||
public enum ApplicationStatus implements EppEnum {
|
||||
ALLOCATED,
|
||||
INVALID,
|
||||
PENDING_ALLOCATION,
|
||||
PENDING_VALIDATION,
|
||||
REJECTED,
|
||||
VALIDATED;
|
||||
|
||||
@Override
|
||||
public String getXmlName() {
|
||||
return UPPER_UNDERSCORE.to(LOWER_CAMEL, name());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this status is a final status - that is, it should not transition to any other
|
||||
* application status after this one.
|
||||
*/
|
||||
public boolean isFinalStatus() {
|
||||
return ALLOCATED.equals(this) || REJECTED.equals(this);
|
||||
}
|
||||
}
|
|
@ -60,6 +60,9 @@ public class LaunchCreateExtension extends LaunchExtension implements CommandExt
|
|||
/**
|
||||
* A Launch Application refers to a registration made during a launch phase when the server
|
||||
* accepts multiple applications for the same domain name.
|
||||
*
|
||||
* <p>This is no longer used, but is retained so incoming commands with this value error out
|
||||
* with a descriptive message rather than failing XML marshalling.
|
||||
*/
|
||||
@XmlEnumValue("application")
|
||||
APPLICATION,
|
||||
|
|
|
@ -1,31 +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.model.domain.launch;
|
||||
|
||||
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
/**
|
||||
* An XML data object that represents a launch extension that may be present on the response to EPP
|
||||
* domain application create commands.
|
||||
*/
|
||||
@XmlRootElement(name = "creData")
|
||||
@XmlType(propOrder = {"phase", "applicationId"})
|
||||
public class LaunchCreateResponseExtension extends LaunchExtension implements ResponseExtension {
|
||||
/** Builder for {@link LaunchCreateResponseExtension}. */
|
||||
public static class Builder
|
||||
extends LaunchExtension.Builder<LaunchCreateResponseExtension, Builder> {}
|
||||
}
|
|
@ -21,5 +21,4 @@ import javax.xml.bind.annotation.XmlRootElement;
|
|||
* commands.
|
||||
*/
|
||||
@XmlRootElement(name = "delete")
|
||||
public class LaunchDeleteExtension
|
||||
extends LaunchExtension implements ApplicationIdTargetExtension {}
|
||||
public class LaunchDeleteExtension extends LaunchExtension {}
|
||||
|
|
|
@ -16,7 +16,6 @@ package google.registry.model.domain.launch;
|
|||
|
||||
import google.registry.model.Buildable.GenericBuilder;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
|
||||
/**
|
||||
|
@ -29,29 +28,17 @@ public abstract class LaunchExtension extends ImmutableObject {
|
|||
/** The launch phase that this domain application was created in. */
|
||||
LaunchPhase phase;
|
||||
|
||||
/** Application ID of the domain application. */
|
||||
@XmlElement(name = "applicationID")
|
||||
String applicationId;
|
||||
|
||||
public LaunchPhase getPhase() {
|
||||
return phase;
|
||||
}
|
||||
|
||||
public String getApplicationId() {
|
||||
return applicationId;
|
||||
}
|
||||
|
||||
/** A builder for constructing {@link LaunchExtension}. */
|
||||
public static class Builder<T extends LaunchExtension, B extends Builder<?, ?>>
|
||||
extends GenericBuilder<T, B> {
|
||||
|
||||
public B setPhase(LaunchPhase phase) {
|
||||
getInstance().phase = phase;
|
||||
return thisCastToDerived();
|
||||
}
|
||||
|
||||
public B setApplicationId(String applicationId) {
|
||||
getInstance().applicationId = applicationId;
|
||||
return thisCastToDerived();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,8 +22,7 @@ import javax.xml.bind.annotation.XmlRootElement;
|
|||
* commands.
|
||||
*/
|
||||
@XmlRootElement(name = "info")
|
||||
public class LaunchInfoExtension
|
||||
extends LaunchExtension implements ApplicationIdTargetExtension {
|
||||
public class LaunchInfoExtension extends LaunchExtension {
|
||||
|
||||
/** Whether or not to include mark information in the response. */
|
||||
@XmlAttribute
|
||||
|
|
|
@ -1,56 +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.model.domain.launch;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.googlecode.objectify.annotation.Embed;
|
||||
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
|
||||
import google.registry.model.mark.Mark;
|
||||
import java.util.List;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
/**
|
||||
* An XML data object that represents a launch extension that may be present on the response to EPP
|
||||
* domain application info commands.
|
||||
*/
|
||||
@Embed
|
||||
@XmlRootElement(name = "infData")
|
||||
@XmlType(propOrder = { "phase", "applicationId", "applicationStatus", "marks"})
|
||||
public class LaunchInfoResponseExtension extends LaunchExtension implements ResponseExtension {
|
||||
|
||||
/** The current status of this application. */
|
||||
@XmlElement(name = "status")
|
||||
ApplicationStatus applicationStatus;
|
||||
|
||||
/** The marks associated with this application. */
|
||||
@XmlElement(name = "mark", namespace = "urn:ietf:params:xml:ns:mark-1.0")
|
||||
List<Mark> marks;
|
||||
|
||||
/** Builder for {@link LaunchInfoResponseExtension}. */
|
||||
public static class Builder
|
||||
extends LaunchExtension.Builder<LaunchInfoResponseExtension, Builder> {
|
||||
public Builder setApplicationStatus(ApplicationStatus applicationStatus) {
|
||||
getInstance().applicationStatus = applicationStatus;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMarks(ImmutableList<Mark> marks) {
|
||||
getInstance().marks = marks;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,15 +14,10 @@
|
|||
|
||||
package google.registry.model.domain.launch;
|
||||
|
||||
import static com.google.common.base.CaseFormat.LOWER_CAMEL;
|
||||
import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
|
||||
import static google.registry.util.TypeUtils.getTypesafeEnumMapping;
|
||||
import static java.util.Objects.hash;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.googlecode.objectify.annotation.Embed;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlValue;
|
||||
|
@ -48,9 +43,9 @@ import javax.xml.bind.annotation.XmlValue;
|
|||
* we will return an error if it's the wrong phase (or if the marks are invalid) even though we
|
||||
* didn't require them.
|
||||
*
|
||||
* <p>This is OK (?) because the Anchor Tenants field is set internally and manually.. The person
|
||||
* who sets it is the one that needs to make sure the domain isn't a trademark and that the fields
|
||||
* are correct.
|
||||
* <p>This is OK (?) because the Anchor Tenants field is set internally and manually. The person who
|
||||
* sets it is the one that needs to make sure the domain isn't a trademark and that the fields are
|
||||
* correct.
|
||||
*/
|
||||
@Embed
|
||||
public class LaunchPhase extends ImmutableObject {
|
||||
|
@ -58,61 +53,33 @@ public class LaunchPhase extends ImmutableObject {
|
|||
/**
|
||||
* The phase during which trademark holders can submit registrations or applications with
|
||||
* trademark information that can be validated by the server.
|
||||
*
|
||||
* This phase works for both start-date and end-data sunrise.
|
||||
*
|
||||
* TODO(b/74006379): maybe make this work for sunrush phase?
|
||||
*/
|
||||
public static final LaunchPhase SUNRISE = create("sunrise", null);
|
||||
|
||||
/**
|
||||
* A post-Sunrise phase when non-trademark holders are allowed to register domain names with steps
|
||||
* taken to address a large volume of initial registrations.
|
||||
*/
|
||||
public static final LaunchPhase LANDRUSH = create("landrush", null);
|
||||
|
||||
/** A combined sunrise/landrush phase. */
|
||||
public static final LaunchPhase SUNRUSH = create("sunrise", "landrush");
|
||||
public static final LaunchPhase SUNRISE = create("sunrise");
|
||||
|
||||
/**
|
||||
* The Trademark Claims phase, as defined in the TMCH Functional Specification, in which a Claims
|
||||
* Notice must be displayed to a prospective registrant of a domain name that matches trademarks.
|
||||
*/
|
||||
public static final LaunchPhase CLAIMS = create("claims", null);
|
||||
public static final LaunchPhase CLAIMS = create("claims");
|
||||
|
||||
/** A post-launch phase that is also referred to as "steady state". */
|
||||
public static final LaunchPhase OPEN = create("open", null);
|
||||
|
||||
/** A custom server launch phase that is defined using the "name" attribute. */
|
||||
public static final LaunchPhase CUSTOM = create("custom", null);
|
||||
|
||||
private static final ImmutableMap<String, LaunchPhase> LAUNCH_PHASES = initEnumMapping();
|
||||
|
||||
/**
|
||||
* Returns a map of the static final fields to their values, case-converted.
|
||||
*/
|
||||
private static ImmutableMap<String, LaunchPhase> initEnumMapping() {
|
||||
ImmutableMap.Builder<String, LaunchPhase> builder = new ImmutableMap.Builder<>();
|
||||
for (Entry<String, LaunchPhase> entry : getTypesafeEnumMapping(LaunchPhase.class).entrySet()) {
|
||||
builder.put(UPPER_UNDERSCORE.to(LOWER_CAMEL, entry.getKey()), entry.getValue());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
public static final LaunchPhase OPEN = create("open");
|
||||
|
||||
/** Private create function for the typesafe enum pattern. */
|
||||
public static LaunchPhase create(String phase, String subphase) {
|
||||
public static LaunchPhase create(String phase) {
|
||||
LaunchPhase instance = new LaunchPhase();
|
||||
instance.phase = phase;
|
||||
instance.subphase = subphase;
|
||||
return instance;
|
||||
}
|
||||
|
||||
@XmlValue
|
||||
String phase;
|
||||
@XmlValue String phase;
|
||||
|
||||
/**
|
||||
* Holds the name of a custom phase if the main phase is "custom", or a sub-phase for all other
|
||||
* values.
|
||||
*
|
||||
* <p>This is currently unused, but is retained so that incoming XMLs that include a subphase can
|
||||
* have it be reflected back.
|
||||
*/
|
||||
@XmlAttribute(name = "name")
|
||||
String subphase;
|
||||
|
@ -121,14 +88,6 @@ public class LaunchPhase extends ImmutableObject {
|
|||
return phase;
|
||||
}
|
||||
|
||||
public String getSubphase() {
|
||||
return subphase;
|
||||
}
|
||||
|
||||
public static LaunchPhase fromValue(String value) {
|
||||
return LAUNCH_PHASES.get(value);
|
||||
}
|
||||
|
||||
/** A special equals implementation that only considers the string value. */
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
|
|
|
@ -21,5 +21,4 @@ import javax.xml.bind.annotation.XmlRootElement;
|
|||
* commands.
|
||||
*/
|
||||
@XmlRootElement(name = "update")
|
||||
public class LaunchUpdateExtension
|
||||
extends LaunchExtension implements ApplicationIdTargetExtension {}
|
||||
public class LaunchUpdateExtension extends LaunchExtension {}
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
|
||||
package google.registry.model.domain.rgp;
|
||||
|
||||
import static com.google.common.base.Predicates.equalTo;
|
||||
import static com.google.common.base.Predicates.not;
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
@ -77,18 +75,6 @@ public enum GracePeriodStatus implements EppEnum {
|
|||
*/
|
||||
PENDING_RESTORE("pendingRestore"),
|
||||
|
||||
/**
|
||||
* This grace period is provided after the allocation of a domain name that was applied for during
|
||||
* sunrise or landrush. If the domain name is deleted by the registrar during this period, the
|
||||
* registry provides a credit to the registrar for the cost of the registration. This grace period
|
||||
* is cancelled when any nameservers are set on the domain, at which point it converts to a
|
||||
* standard add grace period.
|
||||
*
|
||||
* <p>Note that this status shows up as "addPeriod" in XML, which is the same as the add grace
|
||||
* period. This is done deliberately so as not to break the standard EPP schema.
|
||||
*/
|
||||
SUNRUSH_ADD("addPeriod"),
|
||||
|
||||
/**
|
||||
* This grace period is provided after the successful transfer of domain name registration
|
||||
* sponsorship from one registrar to another registrar. If the domain name is deleted by the new
|
||||
|
@ -100,7 +86,6 @@ public enum GracePeriodStatus implements EppEnum {
|
|||
/** Provide a quick lookup of GracePeriodStatus from XML name. */
|
||||
private static final ImmutableMap<String, GracePeriodStatus> XML_NAME_TO_GRACE_PERIOD_STATUS =
|
||||
Stream.of(GracePeriodStatus.values())
|
||||
.filter(not(equalTo(SUNRUSH_ADD)))
|
||||
.collect(
|
||||
toImmutableMap(
|
||||
(GracePeriodStatus gracePeriodStatus) -> gracePeriodStatus.xmlName,
|
||||
|
|
|
@ -19,7 +19,6 @@ import static com.google.common.collect.Maps.uniqueIndex;
|
|||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.domain.allocate.AllocateCreateExtension;
|
||||
import google.registry.model.domain.fee06.FeeCheckCommandExtensionV06;
|
||||
import google.registry.model.domain.fee06.FeeCheckResponseExtensionV06;
|
||||
import google.registry.model.domain.fee11.FeeCheckCommandExtensionV11;
|
||||
|
@ -55,7 +54,6 @@ public class ProtocolDefinition {
|
|||
FEE_0_6(FeeCheckCommandExtensionV06.class, FeeCheckResponseExtensionV06.class, true),
|
||||
FEE_0_11(FeeCheckCommandExtensionV11.class, FeeCheckResponseExtensionV11.class, true),
|
||||
FEE_0_12(FeeCheckCommandExtensionV12.class, FeeCheckResponseExtensionV12.class, true),
|
||||
ALLOCATE_1_0(AllocateCreateExtension.class, null, false),
|
||||
METADATA_1_0(MetadataExtension.class, null, false);
|
||||
|
||||
private final Class<? extends CommandExtension> commandExtensionClass;
|
||||
|
|
|
@ -21,7 +21,6 @@ import static com.google.common.base.Strings.nullToEmpty;
|
|||
import com.google.common.collect.ImmutableSet;
|
||||
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.translators.EnumToAttributeAdapter.EppEnum;
|
||||
|
@ -77,9 +76,9 @@ public enum StatusValue implements EppEnum {
|
|||
/**
|
||||
* A status for a resource undergoing asynchronous creation.
|
||||
*
|
||||
* <p>We only use this for unallocated applications.
|
||||
* <p>This status is here for completeness, but it is not used by our system.
|
||||
*/
|
||||
PENDING_CREATE(AllowedOn.APPLICATIONS),
|
||||
PENDING_CREATE(AllowedOn.NONE),
|
||||
|
||||
/**
|
||||
* A status for a resource indicating that deletion has been requested but has not yet happened.
|
||||
|
@ -92,18 +91,16 @@ public enum StatusValue implements EppEnum {
|
|||
* Otherwise, domains go through an extended deletion process, consisting of a 30-day redemption
|
||||
* grace period followed by a 5-day "pending delete" period before they are actually 100% deleted.
|
||||
* These domains have the PENDING_DELETE status throughout that 35-day window.
|
||||
*
|
||||
* <p>Applications are deleted synchronously and never have this status.
|
||||
*/
|
||||
PENDING_DELETE(AllowedOn.ALL_BUT_APPLICATIONS),
|
||||
PENDING_DELETE(AllowedOn.ALL),
|
||||
|
||||
/**
|
||||
* A status for a resource with an unresolved transfer request.
|
||||
*
|
||||
* <p>Applications can't be transferred. Hosts transfer indirectly via superordinate domain.
|
||||
* <p>Hosts transfer indirectly via superordinate domain.
|
||||
*/
|
||||
// TODO(b/34844887): Remove PENDING_TRANSFER from all host resources and forbid it here.
|
||||
PENDING_TRANSFER(AllowedOn.ALL_BUT_APPLICATIONS),
|
||||
PENDING_TRANSFER(AllowedOn.ALL),
|
||||
|
||||
/**
|
||||
* A status for a resource undergoing an asynchronous update.
|
||||
|
@ -130,11 +127,9 @@ public enum StatusValue implements EppEnum {
|
|||
|
||||
/** Enum to help clearly list which resource types a status value is allowed to be present on. */
|
||||
private enum AllowedOn {
|
||||
ALL(ContactResource.class, DomainApplication.class, DomainResource.class, HostResource.class),
|
||||
ALL(ContactResource.class, DomainResource.class, HostResource.class),
|
||||
NONE,
|
||||
DOMAINS(DomainResource.class),
|
||||
APPLICATIONS(DomainApplication.class),
|
||||
ALL_BUT_APPLICATIONS(ContactResource.class, DomainResource.class, HostResource.class);
|
||||
DOMAINS(DomainResource.class);
|
||||
|
||||
private final ImmutableSet<Class<? extends EppResource>> classes;
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ import com.google.common.collect.ImmutableSet;
|
|||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.contact.ContactCommand;
|
||||
import google.registry.model.domain.DomainCommand;
|
||||
import google.registry.model.domain.allocate.AllocateCreateExtension;
|
||||
import google.registry.model.domain.fee06.FeeCheckCommandExtensionV06;
|
||||
import google.registry.model.domain.fee06.FeeCreateCommandExtensionV06;
|
||||
import google.registry.model.domain.fee06.FeeInfoCommandExtensionV06;
|
||||
|
@ -328,8 +327,6 @@ public class EppInput extends ImmutableObject {
|
|||
|
||||
/** Zero or more command extensions. */
|
||||
@XmlElementRefs({
|
||||
// allocate create extension
|
||||
@XmlElementRef(type = AllocateCreateExtension.class),
|
||||
// allocation token extension
|
||||
@XmlElementRef(type = AllocationTokenExtension.class),
|
||||
// fee extension version 0.6
|
||||
|
|
|
@ -43,8 +43,6 @@ import google.registry.model.domain.fee12.FeeRenewResponseExtensionV12;
|
|||
import google.registry.model.domain.fee12.FeeTransferResponseExtensionV12;
|
||||
import google.registry.model.domain.fee12.FeeUpdateResponseExtensionV12;
|
||||
import google.registry.model.domain.launch.LaunchCheckResponseExtension;
|
||||
import google.registry.model.domain.launch.LaunchCreateResponseExtension;
|
||||
import google.registry.model.domain.launch.LaunchInfoResponseExtension;
|
||||
import google.registry.model.domain.rgp.RgpInfoExtension;
|
||||
import google.registry.model.domain.secdns.SecDnsInfoExtension;
|
||||
import google.registry.model.eppcommon.Trid;
|
||||
|
@ -139,8 +137,6 @@ public class EppResponse extends ImmutableObject implements ResponseOrGreeting {
|
|||
@XmlElementRef(type = FeeTransferResponseExtensionV12.class),
|
||||
@XmlElementRef(type = FeeUpdateResponseExtensionV12.class),
|
||||
@XmlElementRef(type = LaunchCheckResponseExtension.class),
|
||||
@XmlElementRef(type = LaunchCreateResponseExtension.class),
|
||||
@XmlElementRef(type = LaunchInfoResponseExtension.class),
|
||||
@XmlElementRef(type = RgpInfoExtension.class),
|
||||
@XmlElementRef(type = SecDnsInfoExtension.class) })
|
||||
@XmlElementWrapper(name = "extension")
|
||||
|
|
|
@ -1,137 +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.model.index;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.util.CollectionUtils.isNullOrEmpty;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
import com.googlecode.objectify.annotation.Id;
|
||||
import google.registry.model.BackupGroupRoot;
|
||||
import google.registry.model.annotations.ReportedOn;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
import google.registry.util.CollectionUtils;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* Entity for tracking all domain applications with a given fully qualified domain name.
|
||||
*
|
||||
* <p>Since this resource is always kept up to date as additional domain applications are created,
|
||||
* it is never necessary to query them explicitly from Datastore.
|
||||
*/
|
||||
@ReportedOn
|
||||
@Entity
|
||||
public class DomainApplicationIndex extends BackupGroupRoot {
|
||||
|
||||
@Id
|
||||
String fullyQualifiedDomainName;
|
||||
|
||||
/**
|
||||
* A set of all domain applications with this fully qualified domain name. Never null or empty.
|
||||
*
|
||||
* <p>Although this stores {@link Key}s it is named "references" for historical reasons.
|
||||
*/
|
||||
Set<Key<DomainApplication>> references;
|
||||
|
||||
/** Returns a cloned list of all keys on this index. */
|
||||
public ImmutableSet<Key<DomainApplication>> getKeys() {
|
||||
return ImmutableSet.copyOf(references);
|
||||
}
|
||||
|
||||
public String getFullyQualifiedDomainName() {
|
||||
return fullyQualifiedDomainName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DomainApplicationIndex with the specified list of keys.
|
||||
*
|
||||
* <p>Only use this method for data migrations. You probably want {@link #createUpdatedInstance}.
|
||||
*/
|
||||
public static DomainApplicationIndex createWithSpecifiedKeys(
|
||||
String fullyQualifiedDomainName, ImmutableSet<Key<DomainApplication>> keys) {
|
||||
checkArgument(!isNullOrEmpty(fullyQualifiedDomainName),
|
||||
"fullyQualifiedDomainName must not be null or empty.");
|
||||
checkArgument(!isNullOrEmpty(keys), "Keys must not be null or empty.");
|
||||
DomainApplicationIndex instance = new DomainApplicationIndex();
|
||||
instance.fullyQualifiedDomainName = fullyQualifiedDomainName;
|
||||
instance.references = keys;
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static Key<DomainApplicationIndex> createKey(DomainApplication application) {
|
||||
return Key.create(DomainApplicationIndex.class, application.getFullyQualifiedDomainName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of all active DomainApplications for the given fully qualified domain name.
|
||||
*
|
||||
* <p>Note that loading the individual applications referenced by the keys are explicitly
|
||||
* non-transactional. This is to avoid potentially over-enlisting multiple entity groups within a
|
||||
* transaction.
|
||||
*
|
||||
* <p>Consequently within a transaction this method will not return any applications that are not
|
||||
* yet committed to datastore, even if called on an updated DomainApplicationIndex instance
|
||||
* storing keys to those applications.
|
||||
*/
|
||||
public static ImmutableSet<DomainApplication> loadActiveApplicationsByDomainName(
|
||||
String fullyQualifiedDomainName, final DateTime now) {
|
||||
final DomainApplicationIndex index = load(fullyQualifiedDomainName);
|
||||
if (index == null) {
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
// Perform eventually consistent query, to avoid overenlisting cross entity groups
|
||||
return ofy().doTransactionless(() -> {
|
||||
ImmutableSet.Builder<DomainApplication> apps = new ImmutableSet.Builder<>();
|
||||
for (DomainApplication app : ofy().load().keys(index.getKeys()).values()) {
|
||||
if (app.getDeletionTime().isAfter(now)) {
|
||||
apps.add(app);
|
||||
}
|
||||
}
|
||||
return apps.build();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the DomainApplicationIndex for the given fully qualified domain name.
|
||||
*
|
||||
* <p>Note that this can return null if there are no domain applications for this fully qualified
|
||||
* domain name.
|
||||
*/
|
||||
@Nullable
|
||||
public static DomainApplicationIndex load(String fullyQualifiedDomainName) {
|
||||
return ofy().load().type(DomainApplicationIndex.class).id(fullyQualifiedDomainName).now();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a new DomainApplicationIndex for this resource or updates the existing one.
|
||||
*
|
||||
* <p>This is the preferred method for creating an instance of DomainApplicationIndex because this
|
||||
* performs the correct merging logic to add the given domain application to an existing index if
|
||||
* there is one.
|
||||
*/
|
||||
public static DomainApplicationIndex createUpdatedInstance(DomainApplication application) {
|
||||
DomainApplicationIndex existing = load(application.getFullyQualifiedDomainName());
|
||||
ImmutableSet<Key<DomainApplication>> newKeys = CollectionUtils.union(
|
||||
(existing == null ? ImmutableSet.of() : existing.getKeys()),
|
||||
Key.create(application));
|
||||
return createWithSpecifiedKeys(application.getFullyQualifiedDomainName(), newKeys);
|
||||
}
|
||||
}
|
|
@ -32,9 +32,7 @@ import google.registry.model.EppResource;
|
|||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.annotations.ExternalMessagingName;
|
||||
import google.registry.model.domain.DomainRenewData;
|
||||
import google.registry.model.domain.launch.LaunchInfoResponseExtension;
|
||||
import google.registry.model.eppoutput.EppResponse.ResponseData;
|
||||
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
|
||||
import google.registry.model.poll.PendingActionNotificationResponse.ContactPendingActionNotificationResponse;
|
||||
import google.registry.model.poll.PendingActionNotificationResponse.DomainPendingActionNotificationResponse;
|
||||
import google.registry.model.poll.PendingActionNotificationResponse.HostPendingActionNotificationResponse;
|
||||
|
@ -57,15 +55,14 @@ import org.joda.time.DateTime;
|
|||
*
|
||||
* <p>Poll messages are parented off of the {@link HistoryEntry} that resulted in their creation.
|
||||
* This means that poll messages are contained in the Datastore entity group of the parent {@link
|
||||
* EppResource} (which can be a domain, application, contact, or host). It is thus possible to
|
||||
* perform a strongly consistent query to find all poll messages associated with a given EPP
|
||||
* resource.
|
||||
* EppResource} (which can be a domain, contact, or host). It is thus possible to perform a strongly
|
||||
* consistent query to find all poll messages associated with a given EPP resource.
|
||||
*
|
||||
* <p>Poll messages are identified externally by registrars using the format defined in {@link
|
||||
* PollMessageExternalKeyConverter}.
|
||||
*
|
||||
* @see <a href="https://tools.ietf.org/html/rfc5730#section-2.9.2.3">
|
||||
* RFC5730 - EPP - <poll> Command</a>
|
||||
* @see <a href="https://tools.ietf.org/html/rfc5730#section-2.9.2.3">RFC5730 - EPP - <poll>
|
||||
* Command</a>
|
||||
*/
|
||||
@Entity
|
||||
@ExternalMessagingName("message")
|
||||
|
@ -113,8 +110,6 @@ public abstract class PollMessage extends ImmutableObject
|
|||
|
||||
public abstract ImmutableList<ResponseData> getResponseData();
|
||||
|
||||
public abstract ImmutableList<ResponseExtension> getResponseExtensions();
|
||||
|
||||
/** Override Buildable.asBuilder() to give this method stronger typing. */
|
||||
@Override
|
||||
public abstract Builder<?, ?> asBuilder();
|
||||
|
@ -193,15 +188,6 @@ public abstract class PollMessage extends ImmutableObject
|
|||
List<DomainTransferResponse> domainTransferResponses;
|
||||
List<HostPendingActionNotificationResponse> hostPendingActionNotificationResponses;
|
||||
|
||||
// Extensions. Objectify cannot persist a base class type, so we must have a separate field
|
||||
// to hold every possible derived type of ResponseExtensions that we might store.
|
||||
//
|
||||
// Note that we cannot store a list of LaunchInfoResponseExtension objects since it contains a
|
||||
// list of embedded Mark objects, and embedded lists of lists are not allowed. This shouldn't
|
||||
// matter since there's no scenario where multiple launch info response extensions are ever
|
||||
// returned.
|
||||
LaunchInfoResponseExtension launchInfoResponseExtension;
|
||||
|
||||
@Override
|
||||
public Builder asBuilder() {
|
||||
return new Builder(clone(this));
|
||||
|
@ -218,17 +204,11 @@ public abstract class PollMessage extends ImmutableObject
|
|||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<ResponseExtension> getResponseExtensions() {
|
||||
return (launchInfoResponseExtension == null)
|
||||
? ImmutableList.of()
|
||||
: ImmutableList.of(launchInfoResponseExtension);
|
||||
}
|
||||
|
||||
/** A builder for {@link OneTime} since it is immutable. */
|
||||
public static class Builder extends PollMessage.Builder<OneTime, Builder> {
|
||||
|
||||
public Builder() {}
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
private Builder(OneTime instance) {
|
||||
super(instance);
|
||||
|
@ -272,18 +252,6 @@ public abstract class PollMessage extends ImmutableObject
|
|||
.collect(toImmutableList()));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setResponseExtensions(
|
||||
ImmutableList<? extends ResponseExtension> responseExtensions) {
|
||||
getInstance().launchInfoResponseExtension =
|
||||
responseExtensions
|
||||
.stream()
|
||||
.filter(LaunchInfoResponseExtension.class::isInstance)
|
||||
.map(LaunchInfoResponseExtension.class::cast)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -320,11 +288,6 @@ public abstract class PollMessage extends ImmutableObject
|
|||
DomainRenewData.create(getTargetId(), getEventTime().plusYears(1)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<ResponseExtension> getResponseExtensions() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder asBuilder() {
|
||||
return new Builder(clone(this));
|
||||
|
|
|
@ -16,7 +16,7 @@ package google.registry.model.pricing;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Strings.emptyToNull;
|
||||
import static google.registry.model.registry.Registry.TldState.SUNRISE;
|
||||
import static google.registry.model.registry.Registry.TldState.START_DATE_SUNRISE;
|
||||
import static google.registry.model.registry.label.PremiumListUtils.getPremiumPrice;
|
||||
import static google.registry.model.registry.label.ReservationType.NAME_COLLISION;
|
||||
import static google.registry.model.registry.label.ReservedList.getReservationTypes;
|
||||
|
@ -45,7 +45,7 @@ public final class StaticPremiumListPricingEngine implements PremiumPricingEngin
|
|||
Registry registry = Registry.get(checkNotNull(tld, "tld"));
|
||||
Optional<Money> premiumPrice = getPremiumPrice(label, registry);
|
||||
boolean isNameCollisionInSunrise =
|
||||
registry.getTldState(priceTime).equals(SUNRISE)
|
||||
registry.getTldState(priceTime).equals(START_DATE_SUNRISE)
|
||||
&& getReservationTypes(label, tld).contains(NAME_COLLISION);
|
||||
String feeClass = emptyToNull(Joiner.on('-').skipNulls().join(
|
||||
premiumPrice.isPresent() ? "premium" : null,
|
||||
|
|
|
@ -97,7 +97,6 @@ public class Registry extends ImmutableObject implements Buildable {
|
|||
public static final boolean DEFAULT_ESCROW_ENABLED = false;
|
||||
public static final boolean DEFAULT_DNS_PAUSED = false;
|
||||
public static final Duration DEFAULT_ADD_GRACE_PERIOD = Duration.standardDays(5);
|
||||
public static final Duration DEFAULT_SUNRUSH_ADD_GRACE_PERIOD = Duration.standardDays(5);
|
||||
public static final Duration DEFAULT_AUTO_RENEW_GRACE_PERIOD = Duration.standardDays(45);
|
||||
public static final Duration DEFAULT_REDEMPTION_GRACE_PERIOD = Duration.standardDays(30);
|
||||
public static final Duration DEFAULT_RENEW_GRACE_PERIOD = Duration.standardDays(5);
|
||||
|
@ -126,28 +125,10 @@ public class Registry extends ImmutableObject implements Buildable {
|
|||
* sequence of states (ignoring {@link #PDT} which is a pseudo-state).
|
||||
*/
|
||||
public enum TldState {
|
||||
|
||||
/** The state of not yet being delegated to this registry in the root zone by IANA. */
|
||||
PREDELEGATION,
|
||||
|
||||
/**
|
||||
* The state in which only trademark holders can submit applications for domains. Doing so
|
||||
* requires a claims notice to be submitted with the application.
|
||||
*/
|
||||
SUNRISE,
|
||||
|
||||
/**
|
||||
* The state representing the overlap of {@link #SUNRISE} with a "landrush" state in which
|
||||
* anyone can submit an application for a domain name. Sunrise applications may continue during
|
||||
* landrush, so we model the overlap as a distinct state named "sunrush".
|
||||
*/
|
||||
SUNRUSH,
|
||||
|
||||
/**
|
||||
* The state in which anyone can submit an application for a domain name. Sunrise applications
|
||||
* are not allowed during this phase.
|
||||
*/
|
||||
LANDRUSH,
|
||||
|
||||
/**
|
||||
* The state in which only trademark holders can submit a "create" request. It is identical to
|
||||
* {@link #GENERAL_AVAILABILITY} in all other respects.
|
||||
|
@ -155,9 +136,9 @@ public class Registry extends ImmutableObject implements Buildable {
|
|||
START_DATE_SUNRISE,
|
||||
|
||||
/**
|
||||
* A state in which no domain operations are permitted. Generally used after sunrise or landrush
|
||||
* to allocate uncontended applications and send contended applications to auction. This state
|
||||
* is special in that it has no ordering constraints and can appear after any phase.
|
||||
* A state in which no domain operations are permitted. Generally used between sunrise and
|
||||
* general availability. This state is special in that it has no ordering constraints and can
|
||||
* appear after any phase.
|
||||
*/
|
||||
QUIET_PERIOD,
|
||||
|
||||
|
@ -373,9 +354,6 @@ public class Registry extends ImmutableObject implements Buildable {
|
|||
/** The length of the anchor tenant add grace period for this TLD. */
|
||||
Duration anchorTenantAddGracePeriodLength = DEFAULT_ANCHOR_TENANT_ADD_GRACE_PERIOD;
|
||||
|
||||
/** The length of the add grace period during sunrush for this TLD. */
|
||||
Duration sunrushAddGracePeriodLength = DEFAULT_SUNRUSH_ADD_GRACE_PERIOD;
|
||||
|
||||
/** The length of the auto renew grace period for this TLD. */
|
||||
Duration autoRenewGracePeriodLength = DEFAULT_AUTO_RENEW_GRACE_PERIOD;
|
||||
|
||||
|
@ -499,10 +477,6 @@ public class Registry extends ImmutableObject implements Buildable {
|
|||
return addGracePeriodLength;
|
||||
}
|
||||
|
||||
public Duration getSunrushAddGracePeriodLength() {
|
||||
return sunrushAddGracePeriodLength;
|
||||
}
|
||||
|
||||
public Duration getAutoRenewGracePeriodLength() {
|
||||
return autoRenewGracePeriodLength;
|
||||
}
|
||||
|
@ -720,14 +694,6 @@ public class Registry extends ImmutableObject implements Buildable {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder setSunrushAddGracePeriodLength(Duration sunrushAddGracePeriodLength) {
|
||||
checkArgument(
|
||||
sunrushAddGracePeriodLength.isLongerThan(Duration.ZERO),
|
||||
"sunrushAddGracePeriodLength must be non-zero");
|
||||
getInstance().sunrushAddGracePeriodLength = sunrushAddGracePeriodLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Warning! Changing this will affect the billing time of autorenew events in the past. */
|
||||
public Builder setAutoRenewGracePeriodLength(Duration autoRenewGracePeriodLength) {
|
||||
checkArgument(
|
||||
|
|
|
@ -50,11 +50,15 @@ public class HistoryEntry extends ImmutableObject implements Buildable {
|
|||
CONTACT_TRANSFER_REJECT,
|
||||
CONTACT_TRANSFER_REQUEST,
|
||||
CONTACT_UPDATE,
|
||||
/**
|
||||
* Used for history entries that were allocated as a result of a domain application.
|
||||
*
|
||||
* <p>Domain applications (and thus allocating from an application) no longer exist, but we have
|
||||
* existing domains in the system that were created via allocation and thus have history entries
|
||||
* of this type under them, so this is retained for legacy purposes.
|
||||
*/
|
||||
@Deprecated
|
||||
DOMAIN_ALLOCATE,
|
||||
DOMAIN_APPLICATION_CREATE,
|
||||
DOMAIN_APPLICATION_DELETE,
|
||||
DOMAIN_APPLICATION_UPDATE,
|
||||
DOMAIN_APPLICATION_STATUS_UPDATE,
|
||||
/**
|
||||
* Used for domain registration autorenews explicitly logged by
|
||||
* {@link google.registry.batch.ExpandRecurringBillingEventsAction}.
|
||||
|
|
|
@ -34,7 +34,6 @@ import google.registry.tools.server.CreatePremiumListAction;
|
|||
import google.registry.tools.server.DeleteEntityAction;
|
||||
import google.registry.tools.server.GenerateZoneFilesAction;
|
||||
import google.registry.tools.server.KillAllCommitLogsAction;
|
||||
import google.registry.tools.server.KillAllDomainApplicationsAction;
|
||||
import google.registry.tools.server.KillAllEppResourcesAction;
|
||||
import google.registry.tools.server.ListDomainsAction;
|
||||
import google.registry.tools.server.ListHostsAction;
|
||||
|
@ -70,7 +69,6 @@ interface ToolsRequestComponent {
|
|||
FlowComponent.Builder flowComponentBuilder();
|
||||
GenerateZoneFilesAction generateZoneFilesAction();
|
||||
KillAllCommitLogsAction killAllCommitLogsAction();
|
||||
KillAllDomainApplicationsAction killAllDomainApplicationsAction();
|
||||
KillAllEppResourcesAction killAllEppResourcesAction();
|
||||
ListDomainsAction listDomainsAction();
|
||||
ListHostsAction listHostsAction();
|
||||
|
|
|
@ -252,8 +252,6 @@ public class RdapJsonFormatter {
|
|||
.put(HistoryEntry.Type.CONTACT_CREATE, RdapEventAction.REGISTRATION)
|
||||
.put(HistoryEntry.Type.CONTACT_DELETE, RdapEventAction.DELETION)
|
||||
.put(HistoryEntry.Type.CONTACT_TRANSFER_APPROVE, RdapEventAction.TRANSFER)
|
||||
.put(HistoryEntry.Type.DOMAIN_APPLICATION_CREATE, RdapEventAction.REGISTRATION)
|
||||
.put(HistoryEntry.Type.DOMAIN_APPLICATION_DELETE, RdapEventAction.DELETION)
|
||||
.put(HistoryEntry.Type.DOMAIN_AUTORENEW, RdapEventAction.REREGISTRATION)
|
||||
.put(HistoryEntry.Type.DOMAIN_CREATE, RdapEventAction.REGISTRATION)
|
||||
.put(HistoryEntry.Type.DOMAIN_DELETE, RdapEventAction.DELETION)
|
||||
|
|
|
@ -29,6 +29,10 @@ import org.joda.time.DateTime;
|
|||
/**
|
||||
* Helper methods for creating tasks containing CSV line data in the lordn-sunrise and lordn-claims
|
||||
* queues based on DomainResource changes.
|
||||
*
|
||||
* <p>Note that, per the <a href="https://tools.ietf.org/html/draft-ietf-regext-tmch-func-spec-04">
|
||||
* TMCH RFC</a>, while the application-datetime data is optional (which we never send because there
|
||||
* start-date sunrise has no applications), its presence in the header is still required.
|
||||
*/
|
||||
public final class LordnTaskUtils {
|
||||
|
||||
|
@ -62,31 +66,25 @@ public final class LordnTaskUtils {
|
|||
|
||||
/** Returns the corresponding CSV LORDN line for a sunrise domain. */
|
||||
public static String getCsvLineForSunriseDomain(DomainResource domain, DateTime transactionTime) {
|
||||
// Only skip nulls in the outer join because only application time is allowed to be null.
|
||||
Joiner joiner = Joiner.on(',');
|
||||
return joiner.skipNulls().join(
|
||||
joiner.join(
|
||||
return Joiner.on(',')
|
||||
.join(
|
||||
domain.getRepoId(),
|
||||
domain.getFullyQualifiedDomainName(),
|
||||
domain.getSmdId(),
|
||||
getIanaIdentifier(domain.getCreationClientId()),
|
||||
transactionTime), // Used as creation time.
|
||||
domain.getApplicationTime()); // This may be null for start-date sunrise or QLP domains.
|
||||
transactionTime); // Used as creation time.
|
||||
}
|
||||
|
||||
/** Returns the corresponding CSV LORDN line for a claims domain. */
|
||||
public static String getCsvLineForClaimsDomain(DomainResource domain, DateTime transactionTime) {
|
||||
// Only skip nulls in the outer join because only application time is allowed to be null.
|
||||
Joiner joiner = Joiner.on(',');
|
||||
return joiner.skipNulls().join(
|
||||
joiner.join(
|
||||
return Joiner.on(',')
|
||||
.join(
|
||||
domain.getRepoId(),
|
||||
domain.getFullyQualifiedDomainName(),
|
||||
domain.getLaunchNotice().getNoticeId().getTcnId(),
|
||||
getIanaIdentifier(domain.getCreationClientId()),
|
||||
transactionTime, // Used as creation time.
|
||||
domain.getLaunchNotice().getAcceptedTime()),
|
||||
domain.getApplicationTime()); // This is usually null except for landrush domains.
|
||||
domain.getLaunchNotice().getAcceptedTime());
|
||||
}
|
||||
|
||||
/** Retrieves the IANA identifier for a registrar based on the client id. */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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())));
|
||||
}
|
||||
}
|
|
@ -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)));
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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}
|
|
@ -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}
|
|
@ -43,24 +43,15 @@ goog.inherits(registry.registrar.Domain,
|
|||
registry.registrar.XmlResourceComponent);
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Launch phase flag. If not SUNRUSH then GA.
|
||||
*/
|
||||
goog.define('registry.registrar.Domain.SUNRUSH', false);
|
||||
|
||||
|
||||
/** @override */
|
||||
registry.registrar.Domain.prototype.newModel = function() {
|
||||
var newModel = {item: {'domain:period': ''}};
|
||||
if (registry.registrar.Domain.SUNRUSH) {
|
||||
newModel.allowSmd = true;
|
||||
}
|
||||
return newModel;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Prepare a fetch query for the domain by its domain application id.
|
||||
* Prepare a fetch query for the domain by its id.
|
||||
* @param {!Object} params should have a name field with a
|
||||
* possibly extended domain name id of the form "example.tld:1234"
|
||||
* where the 1234 is the domain application id assigned by the
|
||||
|
@ -68,24 +59,8 @@ registry.registrar.Domain.prototype.newModel = function() {
|
|||
* @override
|
||||
*/
|
||||
registry.registrar.Domain.prototype.prepareFetch = function(params) {
|
||||
var xml;
|
||||
if (registry.registrar.Domain.SUNRUSH) {
|
||||
var idParts = params.id.split(':');
|
||||
if (idParts.length != 2) {
|
||||
registry.util.butter(
|
||||
'Domain queries during sunrush have the form: ' +
|
||||
'"example.tld:1234", where 1234 is the application ID.');
|
||||
throw Error('Invalid domain name for SUNRUSH, lacking application ID');
|
||||
}
|
||||
params.name = idParts[0];
|
||||
params.applicationID = idParts[1];
|
||||
xml = registry.soy.registrar.domainepp.infoSunrush(
|
||||
/** @type {{applicationID: ?, clTrid: ?, name: ?}} */(params));
|
||||
} else {
|
||||
xml = registry.soy.registrar.domainepp.info(
|
||||
/** @type {{clTrid: ?, id: ?}} */ (params));
|
||||
}
|
||||
return xml.toString();
|
||||
return registry.soy.registrar.domainepp.info(
|
||||
/** @type {{clTrid: ?, id: ?}} */ (params)).toString();
|
||||
};
|
||||
|
||||
|
||||
|
@ -97,11 +72,6 @@ registry.registrar.Domain.prototype.processItem = function() {
|
|||
if (extension && extension['launch:infData']) {
|
||||
var extendedInfData = extension['launch:infData'];
|
||||
|
||||
var applicationID = extendedInfData['launch:applicationID'];
|
||||
if (applicationID) {
|
||||
this.model.item['launch:applicationID'] = applicationID;
|
||||
}
|
||||
|
||||
var mark = extendedInfData['mark:mark'];
|
||||
if (mark) {
|
||||
this.model.item['mark:mark'] = {'keyValue': goog.json.serialize(mark)};
|
||||
|
@ -165,14 +135,8 @@ registry.registrar.Domain.prototype.prepareCreate = function(params) {
|
|||
if (form['smd:encodedSignedMark'] == '') {
|
||||
delete form['smd:encodedSignedMark'];
|
||||
}
|
||||
var xml;
|
||||
if (registry.registrar.Domain.SUNRUSH) {
|
||||
xml = registry.soy.registrar.domainepp.createSunrush(
|
||||
var xml = registry.soy.registrar.domainepp.create(
|
||||
/** @type {{clTrid: ?, item: ?}} */(params));
|
||||
} else {
|
||||
xml = registry.soy.registrar.domainepp.create(
|
||||
/** @type {{clTrid: ?, item: ?}} */(params));
|
||||
}
|
||||
return xml.toString();
|
||||
};
|
||||
|
||||
|
@ -192,19 +156,12 @@ registry.registrar.Domain.prototype.prepareUpdate =
|
|||
this.addRem(form['domain:ns']['domain:hostObj'], 'Hosts', params);
|
||||
}
|
||||
|
||||
var xml;
|
||||
if (registry.registrar.Domain.SUNRUSH) {
|
||||
xml = registry.soy.registrar.domainepp.updateSunrush(
|
||||
/** @type {{clTrid: ?, item: ?}} */(params));
|
||||
nextId += ':' + form['launch:applicationID'];
|
||||
} else {
|
||||
if (form['domain:ns'] && form['domain:ns']['domain:hostObj']) {
|
||||
this.addRem(form['domain:ns']['domain:hostObj'], 'Hosts', params);
|
||||
}
|
||||
this.addRem(form['domain:contact'], 'Contacts', params);
|
||||
xml = registry.soy.registrar.domainepp.update(
|
||||
var xml = registry.soy.registrar.domainepp.update(
|
||||
/** @type {{clTrid: ?, item: ?}} */(params));
|
||||
}
|
||||
|
||||
return xml.toString();
|
||||
};
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
{template .item}
|
||||
{@param item: ?}
|
||||
{@param? readonly: ?} /** passed through to field rendering. */
|
||||
{@param? allowSmd: ?} /** optional flag to allow sunrush smd applications. */
|
||||
{let $isEdit: isNonnull($item['domain:name']) /}
|
||||
<form name="item" class="{css('item')} {css('domain')}">
|
||||
<h1>
|
||||
|
@ -125,16 +124,6 @@
|
|||
{/if}
|
||||
<tr id="domain-hosts-footer"></tr>
|
||||
|
||||
{if isNonnull($item['launch:applicationID'])}
|
||||
<tr class="{css('section-lead')}">
|
||||
<th colspan="2"><h2>Sunrise domain application</h2></th>
|
||||
</tr>
|
||||
{call registry.soy.forms.inputFieldRowWithValue data="all"}
|
||||
{param label: 'Application ID' /}
|
||||
{param name: 'launch:applicationID' /}
|
||||
{param value: $item['launch:applicationID'] /}
|
||||
{/call}
|
||||
{/if}
|
||||
{if isNonnull($item['mark:mark'])}
|
||||
<tr>
|
||||
<td>Mark Data
|
||||
|
@ -143,13 +132,6 @@
|
|||
{$item['mark:mark']['keyValue']}</textarea>
|
||||
</td>
|
||||
</tr>
|
||||
{else}
|
||||
{if $allowSmd}
|
||||
{call registry.soy.forms.textareaFieldRow data="all"}
|
||||
{param label: 'Encoded Signed Mark (base64 encoded, no header or footer)' /}
|
||||
{param name: 'smd:encodedSignedMark' /}
|
||||
{/call}
|
||||
{/if}
|
||||
{/if}
|
||||
</table>
|
||||
{if $isEdit}
|
||||
|
@ -183,7 +165,7 @@
|
|||
|
||||
/* XXX: Should change support for admin/tech. */
|
||||
/**
|
||||
* Update domain. Includes sunrush applicationId if present.
|
||||
* Update domain.
|
||||
*/
|
||||
{template .update}
|
||||
{@param? item: ?}
|
||||
|
@ -210,11 +192,6 @@
|
|||
<input type="hidden"
|
||||
name="domain:name"
|
||||
value="{$item['domain:name']['keyValue']}">
|
||||
{if isNonnull($item['launch:applicationID'])}
|
||||
<input type="hidden"
|
||||
name="launch:applicationID"
|
||||
value="{$item['launch:applicationID']['keyValue']}">
|
||||
{/if}
|
||||
</table>
|
||||
</form>
|
||||
{/template}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
{namespace registry.soy.registrar.domainepp}
|
||||
|
||||
|
||||
/* General Availability. Sunrush down below. */
|
||||
/* General Availability. */
|
||||
/**
|
||||
* Domain create request.
|
||||
*/
|
||||
|
@ -138,106 +138,3 @@
|
|||
{/if}
|
||||
</{$tagName}>
|
||||
{/template}
|
||||
|
||||
|
||||
/* Sunrush. */
|
||||
/**
|
||||
* Domain create request for sunrush.
|
||||
*/
|
||||
{template .createSunrush stricthtml="false"}
|
||||
{@param item: ?}
|
||||
{@param clTrid: ?}
|
||||
<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>{$item['domain:name']}</domain:name>
|
||||
<domain:period unit="y">{$item['domain:period']}</domain:period>
|
||||
{if isNonnull($item['domain:ns']['domain:hostObj'][0])}
|
||||
<domain:ns>
|
||||
<domain:hostObj>{$item['domain:ns']['domain:hostObj'][0]}</domain:hostObj>
|
||||
{if isNonnull($item['domain:ns']['domain:hostObj'][1])}
|
||||
<domain:hostObj>{$item['domain:ns']['domain:hostObj'][1]}</domain:hostObj>
|
||||
{/if}
|
||||
</domain:ns>
|
||||
{/if}
|
||||
<domain:registrant>{$item['domain:registrant']}</domain:registrant>
|
||||
<domain:contact type="admin">{$item['domain:contact'][0]}</domain:contact>
|
||||
<domain:contact type="tech">{$item['domain:contact'][1]}</domain:contact>
|
||||
<domain:authInfo>
|
||||
<domain:pw>{$item['domain:pw']}</domain:pw>
|
||||
</domain:authInfo>
|
||||
</domain:create>
|
||||
</create>
|
||||
<extension>
|
||||
<launch:create xmlns:launch="urn:ietf:params:xml:ns:launch-1.0">
|
||||
<launch:phase name="landrush">sunrise</launch:phase>
|
||||
{if isNonnull($item['smd:encodedSignedMark'])}
|
||||
<smd:encodedSignedMark xmlns:smd="urn:ietf:params:xml:ns:signedMark-1.0"
|
||||
encoding="base64">{$item['smd:encodedSignedMark']}</smd:encodedSignedMark>
|
||||
{/if}
|
||||
</launch:create>
|
||||
</extension>
|
||||
<clTRID>{$clTrid}</clTRID>
|
||||
</command>
|
||||
</epp>
|
||||
{/template}
|
||||
|
||||
|
||||
/**
|
||||
* Domain info request during sunrush.
|
||||
*/
|
||||
{template .infoSunrush stricthtml="false"}
|
||||
{@param name: ?}
|
||||
{@param applicationID: ?}
|
||||
{@param clTrid: ?}
|
||||
<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 hosts="all">{$name}</domain:name>
|
||||
</domain:info>
|
||||
</info>
|
||||
<extension>
|
||||
<launch:info
|
||||
xmlns:launch="urn:ietf:params:xml:ns:launch-1.0"
|
||||
includeMark="true">
|
||||
<launch:phase name="landrush">sunrise</launch:phase>
|
||||
<launch:applicationID>{$applicationID}</launch:applicationID>
|
||||
</launch:info>
|
||||
</extension>
|
||||
<clTRID>{$clTrid}</clTRID>
|
||||
</command>
|
||||
</epp>
|
||||
{/template}
|
||||
|
||||
|
||||
/**
|
||||
* Domain update request.
|
||||
*/
|
||||
{template .updateSunrush stricthtml="false"}
|
||||
{@param item: ?}
|
||||
{@param clTrid: ?}
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<update>
|
||||
<domain:update xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>{$item['domain:name']}</domain:name>
|
||||
<domain:chg>
|
||||
<domain:registrant>{$item['domain:registrant']}</domain:registrant>
|
||||
<domain:authInfo>
|
||||
<domain:pw>{$item['domain:authInfo']['domain:pw']}</domain:pw>
|
||||
</domain:authInfo>
|
||||
</domain:chg>
|
||||
</domain:update>
|
||||
</update>
|
||||
<extension>
|
||||
<launch:update xmlns:launch="urn:ietf:params:xml:ns:launch-1.0">
|
||||
<launch:phase>sunrise</launch:phase>
|
||||
<launch:applicationID>{$item['launch:applicationID']}</launch:applicationID>
|
||||
</launch:update>
|
||||
</extension>
|
||||
<clTRID>{$clTrid}</clTRID>
|
||||
</command>
|
||||
</epp>
|
||||
{/template}
|
||||
|
|
|
@ -23,7 +23,6 @@ import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_HOST_RENAME;
|
|||
import static google.registry.batch.AsyncTaskMetrics.OperationType.DNS_REFRESH;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
import static google.registry.testing.DatastoreHelper.newDomainApplication;
|
||||
import static google.registry.testing.DatastoreHelper.newDomainResource;
|
||||
import static google.registry.testing.DatastoreHelper.newHostResource;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveHost;
|
||||
|
@ -45,7 +44,6 @@ import static org.mockito.Mockito.verify;
|
|||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.batch.AsyncTaskMetrics.OperationResult;
|
||||
import google.registry.batch.RefreshDnsOnHostRenameAction.RefreshDnsOnHostRenameReducer;
|
||||
|
@ -137,11 +135,6 @@ public class RefreshDnsOnHostRenameActionTest
|
|||
@Test
|
||||
public void testSuccess_dnsUpdateEnqueued() throws Exception {
|
||||
HostResource host = persistActiveHost("ns1.example.tld");
|
||||
persistResource(
|
||||
newDomainApplication("notadomain.tld")
|
||||
.asBuilder()
|
||||
.setNameservers(ImmutableSet.of(Key.create(host)))
|
||||
.build());
|
||||
persistResource(newDomainResource("example.tld", host));
|
||||
persistResource(newDomainResource("otherexample.tld", host));
|
||||
persistResource(newDomainResource("untouched.tld", persistActiveHost("ns2.example.tld")));
|
||||
|
|
|
@ -20,7 +20,6 @@ import static google.registry.export.ExportDomainListsAction.ExportDomainListsRe
|
|||
import static google.registry.export.ExportDomainListsAction.ExportDomainListsReducer.REGISTERED_DOMAINS_FILENAME;
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveDomain;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveDomainApplication;
|
||||
import static google.registry.testing.DatastoreHelper.persistDeletedDomain;
|
||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static google.registry.testing.GcsTestingUtils.readGcsFile;
|
||||
|
@ -152,17 +151,4 @@ public class ExportDomainListsActionTest extends MapreduceTestCase<ExportDomainL
|
|||
// tldthree does not have a drive id, so no export to drive is performed.
|
||||
verifyNoMoreInteractions(driveConnection);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_doesntOutputDomainApplications() throws Exception {
|
||||
persistActiveDomain("chilipepper.tld");
|
||||
persistActiveDomainApplication("nagajolokia.tld");
|
||||
runMapreduce();
|
||||
GcsFilename firstTldFile = new GcsFilename("outputbucket", "tld.txt");
|
||||
String tlds = new String(readGcsFile(gcsService, firstTldFile), UTF_8).trim();
|
||||
// Check that it didn't output nagajolokia.tld.
|
||||
assertThat(tlds).isEqualTo("chilipepper.tld");
|
||||
verifyExportedToDrive("brouhaha", "chilipepper.tld");
|
||||
verifyNoMoreInteractions(driveConnection);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ AllocationToken
|
|||
Cancellation
|
||||
ContactResource
|
||||
Cursor
|
||||
DomainApplicationIndex
|
||||
DomainBase
|
||||
EntityGroupRoot
|
||||
EppResourceIndex
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
AllocationToken
|
||||
Cancellation
|
||||
ContactResource
|
||||
DomainApplicationIndex
|
||||
DomainBase
|
||||
EppResourceIndex
|
||||
ForeignKeyContactIndex
|
||||
|
|
|
@ -1,96 +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.flows;
|
||||
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import google.registry.model.registry.Registry.TldState;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.util.DateTimeUtils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Tests for domain application lifecycle. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class EppLifecycleDomainApplicationTest extends EppTestCase {
|
||||
|
||||
private static final DateTime START_OF_GA = DateTime.parse("2014-03-01T00:00:00Z");
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.withTaskQueue()
|
||||
.build();
|
||||
|
||||
@Before
|
||||
public void initTld() {
|
||||
createTld("example", ImmutableSortedMap.of(
|
||||
DateTimeUtils.START_OF_TIME, TldState.SUNRISE,
|
||||
START_OF_GA, TldState.GENERAL_AVAILABILITY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplicationDuringSunrise_doesntCreateDomainWithoutAllocation() throws Exception {
|
||||
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
|
||||
createContactsAndHosts();
|
||||
// Note that the trademark is valid from 2013-08-09 to 2017-07-23, hence the creation in 2014.
|
||||
assertThatCommand("domain_create_sunrise_encoded_mark.xml")
|
||||
.atTime("2014-01-01T00:00:00Z")
|
||||
.hasResponse("domain_create_sunrise_encoded_signed_mark_response.xml");
|
||||
assertThatCommand("domain_info_testvalidate.xml")
|
||||
.atTime("2014-01-01T00:01:00Z")
|
||||
.hasResponse(
|
||||
"response_error.xml",
|
||||
ImmutableMap.of(
|
||||
"CODE", "2303",
|
||||
"MSG", "The domain with given ID (test-validate.example) doesn't exist."));
|
||||
assertThatLogoutSucceeds();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDomainAllocation_succeedsOnlyAsSuperuser() throws Exception {
|
||||
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
|
||||
createContactsAndHosts();
|
||||
assertThatCommand("domain_create_sunrise_encoded_mark.xml")
|
||||
.atTime("2014-01-01T00:00:00Z")
|
||||
.hasResponse("domain_create_sunrise_encoded_signed_mark_response.xml");
|
||||
assertThatCommand("domain_info_testvalidate.xml")
|
||||
.atTime("2014-01-01T00:01:00Z")
|
||||
.hasResponse(
|
||||
"response_error.xml",
|
||||
ImmutableMap.of(
|
||||
"CODE", "2303",
|
||||
"MSG", "The domain with given ID (test-validate.example) doesn't exist."));
|
||||
assertThatCommand("domain_allocate_testvalidate.xml")
|
||||
.atTime(START_OF_GA.plusDays(1))
|
||||
.hasResponse(
|
||||
"response_error.xml",
|
||||
ImmutableMap.of("CODE", "2201", "MSG", "Only a superuser can allocate domains"));
|
||||
setIsSuperuser(true);
|
||||
assertThatCommand("domain_allocate_testvalidate.xml")
|
||||
.atTime(START_OF_GA.plusDays(1).plusMinutes(1))
|
||||
.hasResponse("domain_allocate_response_testvalidate.xml");
|
||||
setIsSuperuser(false);
|
||||
assertThatCommand("domain_info_testvalidate.xml")
|
||||
.atTime(START_OF_GA.plusDays(1).plusMinutes(2))
|
||||
.hasResponse("domain_info_response_testvalidate_ok.xml");
|
||||
}
|
||||
}
|
|
@ -18,6 +18,9 @@ import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
|||
import static google.registry.model.eppoutput.Result.Code.SUCCESS;
|
||||
import static google.registry.model.eppoutput.Result.Code.SUCCESS_AND_CLOSE;
|
||||
import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_ACTION_PENDING;
|
||||
import static google.registry.model.registry.Registry.TldState.GENERAL_AVAILABILITY;
|
||||
import static google.registry.model.registry.Registry.TldState.PREDELEGATION;
|
||||
import static google.registry.model.registry.Registry.TldState.START_DATE_SUNRISE;
|
||||
import static google.registry.testing.DatastoreHelper.assertBillingEventsForResource;
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
import static google.registry.testing.DatastoreHelper.createTlds;
|
||||
|
@ -29,6 +32,7 @@ import static org.joda.money.CurrencyUnit.USD;
|
|||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.google.re2j.Matcher;
|
||||
import com.google.re2j.Pattern;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
|
@ -376,13 +380,11 @@ public class EppLifecycleDomainTest extends EppTestCase {
|
|||
DateTime sunriseDate = DateTime.parse("2000-05-30T00:00:00Z");
|
||||
createTld(
|
||||
"example",
|
||||
ImmutableSortedMap.of(
|
||||
START_OF_TIME,
|
||||
TldState.PREDELEGATION,
|
||||
sunriseDate,
|
||||
TldState.SUNRISE,
|
||||
sunriseDate.plusMonths(2),
|
||||
TldState.GENERAL_AVAILABILITY));
|
||||
new ImmutableSortedMap.Builder<DateTime, TldState>(Ordering.natural())
|
||||
.put(START_OF_TIME, PREDELEGATION)
|
||||
.put(sunriseDate, START_DATE_SUNRISE)
|
||||
.put(sunriseDate.plusMonths(2), GENERAL_AVAILABILITY)
|
||||
.build());
|
||||
|
||||
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
|
||||
|
||||
|
@ -393,7 +395,8 @@ public class EppLifecycleDomainTest extends EppTestCase {
|
|||
.hasResponse(
|
||||
"response_error.xml",
|
||||
ImmutableMap.of(
|
||||
"CODE", "2002", "MSG", "Command is not allowed in the current registry phase"));
|
||||
"CODE", "2002",
|
||||
"MSG", "The current registry phase does not allow for general registrations"));
|
||||
|
||||
assertThatCommand("domain_info_testvalidate.xml")
|
||||
.atTime(sunriseDate.plusDays(1))
|
||||
|
@ -412,8 +415,8 @@ public class EppLifecycleDomainTest extends EppTestCase {
|
|||
createTld(
|
||||
"example",
|
||||
ImmutableSortedMap.of(
|
||||
START_OF_TIME, TldState.PREDELEGATION,
|
||||
gaDate, TldState.GENERAL_AVAILABILITY));
|
||||
START_OF_TIME, PREDELEGATION,
|
||||
gaDate, GENERAL_AVAILABILITY));
|
||||
|
||||
assertThatCommand("login_valid_fee_extension.xml").hasResponse("generic_success_response.xml");
|
||||
|
||||
|
@ -882,9 +885,9 @@ public class EppLifecycleDomainTest extends EppTestCase {
|
|||
createTld(
|
||||
"example",
|
||||
ImmutableSortedMap.of(
|
||||
START_OF_TIME, TldState.PREDELEGATION,
|
||||
sunriseDate, TldState.START_DATE_SUNRISE,
|
||||
gaDate, TldState.GENERAL_AVAILABILITY));
|
||||
START_OF_TIME, PREDELEGATION,
|
||||
sunriseDate, START_DATE_SUNRISE,
|
||||
gaDate, GENERAL_AVAILABILITY));
|
||||
|
||||
assertThatLogin("NewRegistrar", "foo-BAR2")
|
||||
.atTime(sunriseDate.minusDays(3))
|
||||
|
@ -898,13 +901,11 @@ public class EppLifecycleDomainTest extends EppTestCase {
|
|||
.hasResponse(
|
||||
"response_error.xml",
|
||||
ImmutableMap.of(
|
||||
"CODE", "2306",
|
||||
"MSG",
|
||||
"Declared launch extension phase does not match the current registry phase"));
|
||||
"CODE", "2002",
|
||||
"MSG", "The current registry phase does not allow for general registrations"));
|
||||
|
||||
assertThatCommand(
|
||||
"domain_create_no_hosts_or_dsdata.xml",
|
||||
ImmutableMap.of("DOMAIN", "general.example"))
|
||||
"domain_create_no_hosts_or_dsdata.xml", ImmutableMap.of("DOMAIN", "general.example"))
|
||||
.atTime(sunriseDate.minusDays(1))
|
||||
.hasResponse(
|
||||
"response_error.xml",
|
||||
|
@ -912,7 +913,17 @@ public class EppLifecycleDomainTest extends EppTestCase {
|
|||
"CODE", "2002",
|
||||
"MSG", "The current registry phase does not allow for general registrations"));
|
||||
|
||||
// During start-date sunrise, create with mark will succeed but without will fail.
|
||||
// During sunrise, verify that the launch phase must be set to sunrise.
|
||||
assertThatCommand("domain_create_start_date_sunrise_encoded_mark_wrong_phase.xml")
|
||||
.atTime(sunriseDate)
|
||||
.hasResponse(
|
||||
"response_error.xml",
|
||||
ImmutableMap.of(
|
||||
"CODE", "2306",
|
||||
"MSG",
|
||||
"Declared launch extension phase does not match the current registry phase"));
|
||||
|
||||
// During sunrise, create with mark will succeed but without will fail.
|
||||
// We also test we can delete without a mark.
|
||||
assertThatCommand("domain_create_start_date_sunrise_encoded_mark.xml")
|
||||
.atTime(sunriseDate.plusDays(1))
|
||||
|
@ -961,12 +972,7 @@ public class EppLifecycleDomainTest extends EppTestCase {
|
|||
assertThatLogoutSucceeds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that missing type= argument on launch create works in start-date sunrise.
|
||||
*
|
||||
* <p>TODO(b/76095570):have the same exact test on end-date sunrise - using the same .xml file -
|
||||
* that checks that an application was created.
|
||||
*/
|
||||
/** Test that missing type= argument on launch create works in start-date sunrise. */
|
||||
@Test
|
||||
public void testDomainCreation_startDateSunrise_noType() throws Exception {
|
||||
// The signed mark is valid between 2013 and 2017
|
||||
|
@ -975,9 +981,9 @@ public class EppLifecycleDomainTest extends EppTestCase {
|
|||
createTld(
|
||||
"example",
|
||||
ImmutableSortedMap.of(
|
||||
START_OF_TIME, TldState.PREDELEGATION,
|
||||
sunriseDate, TldState.START_DATE_SUNRISE,
|
||||
gaDate, TldState.GENERAL_AVAILABILITY));
|
||||
START_OF_TIME, PREDELEGATION,
|
||||
sunriseDate, START_DATE_SUNRISE,
|
||||
gaDate, GENERAL_AVAILABILITY));
|
||||
|
||||
assertThatLogin("NewRegistrar", "foo-BAR2")
|
||||
.atTime(sunriseDate.minusDays(3))
|
||||
|
|
|
@ -39,7 +39,6 @@ import google.registry.flows.EppTestComponent.FakesAndMocksModule;
|
|||
import google.registry.flows.picker.FlowPicker;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.domain.GracePeriod;
|
||||
import google.registry.model.domain.rgp.GracePeriodStatus;
|
||||
import google.registry.model.eppcommon.ProtocolDefinition;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.eppoutput.EppOutput;
|
||||
|
@ -211,9 +210,7 @@ public abstract class FlowTestCase<F extends Flow> extends ShardableTestCase {
|
|||
((Function<GracePeriod, GracePeriod>)
|
||||
gracePeriod ->
|
||||
GracePeriod.create(
|
||||
gracePeriod.isSunrushAddGracePeriod()
|
||||
? GracePeriodStatus.SUNRUSH_ADD
|
||||
: gracePeriod.getType(),
|
||||
gracePeriod.getType(),
|
||||
gracePeriod.getExpirationTime(),
|
||||
gracePeriod.getClientId(),
|
||||
null))
|
||||
|
|
|
@ -17,7 +17,6 @@ package google.registry.flows;
|
|||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
||||
import static google.registry.model.EppResourceUtils.loadDomainApplication;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.model.tmch.ClaimsListShardTest.createTestClaimsListShard;
|
||||
import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions;
|
||||
|
@ -33,8 +32,6 @@ import com.google.common.testing.TestLogHandler;
|
|||
import com.googlecode.objectify.Key;
|
||||
import google.registry.flows.FlowUtils.NotLoggedInException;
|
||||
import google.registry.model.EppResource;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
import google.registry.model.domain.launch.ApplicationIdTargetExtension;
|
||||
import google.registry.model.eppcommon.Trid;
|
||||
import google.registry.model.eppinput.EppInput.ResourceCommandWrapper;
|
||||
import google.registry.model.eppinput.ResourceCommand;
|
||||
|
@ -44,7 +41,6 @@ import google.registry.model.tmch.ClaimsListShard.ClaimsListRevision;
|
|||
import google.registry.model.tmch.ClaimsListShard.ClaimsListSingleton;
|
||||
import google.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
import google.registry.util.TypeUtils.TypeInstantiator;
|
||||
import java.util.Optional;
|
||||
import java.util.logging.Level;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.DateTime;
|
||||
|
@ -85,11 +81,6 @@ public abstract class ResourceFlowTestCase<F extends Flow, R extends EppResource
|
|||
return reloadResourceByForeignKey(clock.nowUtc());
|
||||
}
|
||||
|
||||
protected DomainApplication reloadDomainApplication() throws Exception {
|
||||
ofy().clearSessionCache();
|
||||
return loadDomainApplication(getUniqueIdFromCommand(), clock.nowUtc()).get();
|
||||
}
|
||||
|
||||
protected <T extends EppResource> T reloadResourceAndCloneAtTime(T resource, DateTime now) {
|
||||
// Force the session to be cleared.
|
||||
ofy().clearSessionCache();
|
||||
|
@ -104,17 +95,8 @@ public abstract class ResourceFlowTestCase<F extends Flow, R extends EppResource
|
|||
.getResourceCommand();
|
||||
}
|
||||
|
||||
/**
|
||||
* We have to duplicate the logic from SingleResourceFlow.getTargetId() here. However, given the
|
||||
* choice between making that method public, and duplicating its logic, it seems better to muddy
|
||||
* the test code rather than the production code.
|
||||
*/
|
||||
protected String getUniqueIdFromCommand() throws Exception {
|
||||
Optional<ApplicationIdTargetExtension> extension =
|
||||
eppLoader.getEpp().getSingleExtension(ApplicationIdTargetExtension.class);
|
||||
return extension.isPresent()
|
||||
? extension.get().getApplicationId()
|
||||
: getResourceCommand().getTargetId();
|
||||
return getResourceCommand().getTargetId();
|
||||
}
|
||||
|
||||
protected Class<R> getResourceClass() {
|
||||
|
|
|
@ -36,18 +36,6 @@ public class TestDomainPricingCustomLogic extends DomainPricingCustomLogic {
|
|||
super(eppInput, sessionMetadata, flowMetadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeesAndCredits customizeApplicationUpdatePrice(
|
||||
ApplicationUpdatePriceParameters priceParameters) {
|
||||
return (priceParameters
|
||||
.domainApplication()
|
||||
.getFullyQualifiedDomainName()
|
||||
.startsWith("non-free-update"))
|
||||
? addCustomFee(
|
||||
priceParameters.feesAndCredits(), Fee.create(ONE_HUNDRED_BUCKS, FeeType.UPDATE))
|
||||
: priceParameters.feesAndCredits();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeesAndCredits customizeRenewPrice(RenewPriceParameters priceParameters) {
|
||||
return (priceParameters.domainName().toString().startsWith("costly-renew"))
|
||||
|
|
|
@ -1,715 +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.flows.domain;
|
||||
|
||||
import static com.google.common.io.BaseEncoding.base16;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.EppResourceUtils.loadDomainApplication;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.testing.DatastoreHelper.assertBillingEvents;
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
import static google.registry.testing.DatastoreHelper.getOnlyHistoryEntryOfType;
|
||||
import static google.registry.testing.DatastoreHelper.newDomainApplication;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveContact;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveDomain;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveHost;
|
||||
import static google.registry.testing.DatastoreHelper.persistDeletedDomain;
|
||||
import static google.registry.testing.DatastoreHelper.persistReservedList;
|
||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static google.registry.testing.DomainApplicationSubject.assertAboutApplications;
|
||||
import static google.registry.testing.DomainResourceSubject.assertAboutDomains;
|
||||
import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions;
|
||||
import static google.registry.testing.JUnitBackports.assertThrows;
|
||||
import static google.registry.testing.TaskQueueHelper.assertDnsTasksEnqueued;
|
||||
import static google.registry.testing.TaskQueueHelper.assertNoDnsTasksEnqueued;
|
||||
import static google.registry.testing.TaskQueueHelper.assertNoTasksEnqueued;
|
||||
import static google.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.ResourceFlowTestCase;
|
||||
import google.registry.flows.domain.DomainAllocateFlow.HasFinalStatusException;
|
||||
import google.registry.flows.domain.DomainAllocateFlow.MissingApplicationException;
|
||||
import google.registry.flows.domain.DomainAllocateFlow.OnlySuperuserCanAllocateException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.ExceedsMaxRegistrationYearsException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.NameserversNotAllowedForDomainException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.NameserversNotAllowedForTldException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.NameserversNotSpecifiedForNameserverRestrictedDomainException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.NameserversNotSpecifiedForTldWithNameserverWhitelistException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.RegistrantNotAllowedException;
|
||||
import google.registry.flows.exceptions.ResourceAlreadyExistsException;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingEvent.Flag;
|
||||
import google.registry.model.billing.BillingEvent.Reason;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
import google.registry.model.domain.DomainResource;
|
||||
import google.registry.model.domain.GracePeriod;
|
||||
import google.registry.model.domain.launch.ApplicationStatus;
|
||||
import google.registry.model.domain.launch.LaunchInfoResponseExtension;
|
||||
import google.registry.model.domain.launch.LaunchNotice;
|
||||
import google.registry.model.domain.launch.LaunchPhase;
|
||||
import google.registry.model.domain.rgp.GracePeriodStatus;
|
||||
import google.registry.model.domain.secdns.DelegationSignerData;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.eppcommon.Trid;
|
||||
import google.registry.model.ofy.ObjectifyService;
|
||||
import google.registry.model.poll.PendingActionNotificationResponse.DomainPendingActionNotificationResponse;
|
||||
import google.registry.model.poll.PollMessage;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.model.registry.Registry.TldState;
|
||||
import google.registry.model.reporting.DomainTransactionRecord;
|
||||
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.smd.EncodedSignedMark;
|
||||
import google.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/** Unit tests for {@link DomainAllocateFlow}. */
|
||||
public class DomainAllocateFlowTest
|
||||
extends ResourceFlowTestCase<DomainAllocateFlow, DomainResource> {
|
||||
|
||||
// These constants come from "domain_allocate.xml" and its variants.
|
||||
private static final DateTime APPLICATION_TIME = DateTime.parse("2010-08-16T10:00:00.0Z");
|
||||
private static final String SMD_ID = "1-1";
|
||||
|
||||
private static final String CLIENT_ID = "TheRegistrar";
|
||||
private static final Trid TRID = Trid.create("ABC-123", "server-trid");
|
||||
|
||||
/** The applicationId, expressed as a base 10 String. */
|
||||
private String applicationId = "2-TLD";
|
||||
private DomainApplication application;
|
||||
private HistoryEntry historyEntry;
|
||||
|
||||
@Before
|
||||
public void initAllocateTest() {
|
||||
setEppInput(
|
||||
"domain_allocate.xml",
|
||||
ImmutableMap.of("APPLICATIONID", "2-TLD", "DOMAIN", "example-one.tld"));
|
||||
clock.setTo(APPLICATION_TIME);
|
||||
}
|
||||
|
||||
private void setupDomainApplication(String tld, TldState tldState) throws Exception {
|
||||
createTld(tld, tldState);
|
||||
persistResource(Registry.get(tld).asBuilder()
|
||||
.setReservedLists(
|
||||
persistReservedList(
|
||||
tld + "-reserved",
|
||||
"reserved-label,FULLY_BLOCKED",
|
||||
"collision-label,NAME_COLLISION"))
|
||||
.setAddGracePeriodLength(Duration.standardMinutes(9))
|
||||
.build());
|
||||
String domainName = getUniqueIdFromCommand();
|
||||
application = persistResource(newDomainApplication(domainName).asBuilder()
|
||||
.setCreationTrid(TRID)
|
||||
.setEncodedSignedMarks(ImmutableList.of(EncodedSignedMark.create("base64", "abcdef")))
|
||||
.setCreationTrid(TRID)
|
||||
.build());
|
||||
for (int i = 1; i <= 14; ++i) {
|
||||
persistActiveHost(String.format("ns%d.example.net", i));
|
||||
}
|
||||
persistActiveContact("jd1234");
|
||||
persistActiveContact("sh8013");
|
||||
clock.setTo(DateTime.parse("2010-09-16T10:00:00.0Z"));
|
||||
}
|
||||
|
||||
private void doSuccessfulTest(int nameservers) throws Exception {
|
||||
assertTransactionalFlow(true);
|
||||
runFlowAssertResponse(
|
||||
CommitMode.LIVE,
|
||||
UserPrivileges.SUPERUSER,
|
||||
loadFile("domain_allocate_response.xml"));
|
||||
// Check that the domain was created and persisted with a history entry.
|
||||
DomainResource domain = reloadResourceByForeignKey();
|
||||
assertAboutDomains().that(domain)
|
||||
.hasOnlyOneHistoryEntryWhich()
|
||||
.hasType(HistoryEntry.Type.DOMAIN_ALLOCATE);
|
||||
historyEntry = getOnlyHistoryEntryOfType(domain, HistoryEntry.Type.DOMAIN_ALLOCATE);
|
||||
|
||||
// The domain gets the sunrush add grace period if no nameservers were set during allocation.
|
||||
boolean sunrushAddGracePeriod = (nameservers == 0);
|
||||
|
||||
// The application should be marked as allocated, with a new history entry.
|
||||
DomainApplication application = loadDomainApplication(applicationId, clock.nowUtc()).get();
|
||||
assertAboutApplications().that(application)
|
||||
.hasApplicationStatus(ApplicationStatus.ALLOCATED).and()
|
||||
.hasHistoryEntryAtIndex(0)
|
||||
.which().hasType(HistoryEntry.Type.DOMAIN_APPLICATION_STATUS_UPDATE);
|
||||
|
||||
String domainName = getUniqueIdFromCommand();
|
||||
// There should be a poll message for the allocated application (and one for generic autorenew).
|
||||
assertPollMessages(
|
||||
new PollMessage.OneTime.Builder()
|
||||
.setClientId(CLIENT_ID)
|
||||
.setEventTime(clock.nowUtc())
|
||||
.setMsg("Domain was allocated")
|
||||
.setResponseData(ImmutableList.of(DomainPendingActionNotificationResponse.create(
|
||||
domainName, true, TRID, clock.nowUtc())))
|
||||
.setResponseExtensions(ImmutableList.of(new LaunchInfoResponseExtension.Builder()
|
||||
.setApplicationId(applicationId)
|
||||
.setPhase(LaunchPhase.SUNRISE) // This comes from newDomainApplication()
|
||||
.setApplicationStatus(ApplicationStatus.ALLOCATED)
|
||||
.build()))
|
||||
.setParent(historyEntry)
|
||||
.build(),
|
||||
new PollMessage.Autorenew.Builder()
|
||||
.setTargetId(domainName)
|
||||
.setClientId(CLIENT_ID)
|
||||
.setEventTime(clock.nowUtc().plusYears(2))
|
||||
.setMsg("Domain was auto-renewed.")
|
||||
.setParent(historyEntry)
|
||||
.build());
|
||||
|
||||
// There should be a bill for the create and a recurring autorenew event.
|
||||
BillingEvent.OneTime createBillingEvent = new BillingEvent.OneTime.Builder()
|
||||
.setReason(Reason.CREATE)
|
||||
.setFlags(ImmutableSet.of(Flag.ALLOCATION, Flag.SUNRISE))
|
||||
.setTargetId(domainName)
|
||||
.setClientId(CLIENT_ID)
|
||||
.setCost(Money.of(USD, 26))
|
||||
.setPeriodYears(2)
|
||||
.setEventTime(clock.nowUtc())
|
||||
.setBillingTime(clock.nowUtc().plus(sunrushAddGracePeriod
|
||||
? Registry.get("tld").getSunrushAddGracePeriodLength()
|
||||
: Registry.get("tld").getAddGracePeriodLength()))
|
||||
.setParent(historyEntry)
|
||||
.build();
|
||||
assertBillingEvents(
|
||||
createBillingEvent,
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setReason(Reason.RENEW)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setTargetId(domainName)
|
||||
.setClientId(CLIENT_ID)
|
||||
.setEventTime(domain.getRegistrationExpirationTime())
|
||||
.setRecurrenceEndTime(END_OF_TIME)
|
||||
.setParent(historyEntry)
|
||||
.build());
|
||||
assertGracePeriods(
|
||||
domain.getGracePeriods(),
|
||||
ImmutableMap.of(
|
||||
GracePeriod.create(
|
||||
sunrushAddGracePeriod ? GracePeriodStatus.SUNRUSH_ADD : GracePeriodStatus.ADD,
|
||||
clock.nowUtc().plus(sunrushAddGracePeriod
|
||||
? Registry.get("tld").getSunrushAddGracePeriodLength()
|
||||
: Registry.get("tld").getAddGracePeriodLength()),
|
||||
CLIENT_ID,
|
||||
null),
|
||||
createBillingEvent));
|
||||
assertThat(ofy().load().key(domain.getAutorenewBillingEvent()).now().getEventTime())
|
||||
.isEqualTo(domain.getRegistrationExpirationTime());
|
||||
|
||||
assertThat(domain.getApplicationTime()).isEqualTo(APPLICATION_TIME);
|
||||
assertThat(domain.getApplication()).isEqualTo(Key.create(application));
|
||||
if (nameservers == 0) {
|
||||
assertNoDnsTasksEnqueued();
|
||||
} else {
|
||||
assertDnsTasksEnqueued(domainName);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
doSuccessfulTest(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_nameserverAndRegistrantWhitelisted() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setAllowedRegistrantContactIds(ImmutableSet.of("jd1234"))
|
||||
.setAllowedFullyQualifiedHostNames(
|
||||
ImmutableSet.of("ns1.example.net", "ns2.example.net"))
|
||||
.build());
|
||||
doSuccessfulTest(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_nameserverNotWhitelisted() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setAllowedRegistrantContactIds(ImmutableSet.of("jd1234"))
|
||||
.setAllowedFullyQualifiedHostNames(ImmutableSet.of("ns2.example.net"))
|
||||
.build());
|
||||
NameserversNotAllowedForTldException thrown =
|
||||
assertThrows(NameserversNotAllowedForTldException.class, this::runFlowAsSuperuser);
|
||||
assertThat(thrown).hasMessageThat().contains("ns1.example.net");
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_registrantNotWhitelisted() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setAllowedRegistrantContactIds(ImmutableSet.of("someone"))
|
||||
.setAllowedFullyQualifiedHostNames(
|
||||
ImmutableSet.of("ns1.example.net", "ns2.example.net"))
|
||||
.build());
|
||||
RegistrantNotAllowedException thrown =
|
||||
assertThrows(RegistrantNotAllowedException.class, this::runFlowAsSuperuser);
|
||||
assertThat(thrown).hasMessageThat().contains("jd1234");
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_emptyNameserverFailsWhitelist() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
setEppInput("domain_allocate_no_nameservers.xml");
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setAllowedRegistrantContactIds(ImmutableSet.of("jd1234"))
|
||||
.setAllowedFullyQualifiedHostNames(ImmutableSet.of("ns1.example.net, ns2.example.net"))
|
||||
.build());
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
NameserversNotSpecifiedForTldWithNameserverWhitelistException.class,
|
||||
this::runFlowAsSuperuser);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_domainNameserverRestricted_allNameserversAllowed() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setReservedLists(
|
||||
persistReservedList(
|
||||
"reserved",
|
||||
"example-one,NAMESERVER_RESTRICTED,"
|
||||
+ "ns1.example.net:ns2.example.net:ns3.example.net"))
|
||||
.build());
|
||||
doSuccessfulTest(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_domainNameserverRestricted_someNameserversDisallowed() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setReservedLists(
|
||||
persistReservedList(
|
||||
"reserved",
|
||||
"example-one,NAMESERVER_RESTRICTED," + "ns2.example.net:ns3.example.net"))
|
||||
.build());
|
||||
NameserversNotAllowedForDomainException thrown =
|
||||
assertThrows(NameserversNotAllowedForDomainException.class, this::runFlowAsSuperuser);
|
||||
assertThat(thrown).hasMessageThat().contains("ns1.example.net");
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_domainNameserverRestricted_noNameservers() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
setEppInput("domain_allocate_no_nameservers.xml");
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setReservedLists(
|
||||
persistReservedList(
|
||||
"reserved",
|
||||
"example-one,NAMESERVER_RESTRICTED," + "ns2.example.net:ns3.example.net"))
|
||||
.build());
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
NameserversNotSpecifiedForNameserverRestrictedDomainException.class,
|
||||
this::runFlowAsSuperuser);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_tldAndDomainNameserversWhitelistBothSatistfied() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setDomainCreateRestricted(true)
|
||||
.setReservedLists(
|
||||
persistReservedList(
|
||||
"reserved",
|
||||
"example-one,NAMESERVER_RESTRICTED,"
|
||||
+ "ns1.example.net:ns2.example.net:ns3.example.net"))
|
||||
.setAllowedFullyQualifiedHostNames(
|
||||
ImmutableSet.of("ns1.example.net", "ns2.example.net", "ns4.example.net"))
|
||||
.build());
|
||||
doSuccessfulTest(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_domainNameserversDisallowed_tldNameserversAllowed() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setReservedLists(
|
||||
persistReservedList(
|
||||
"reserved",
|
||||
"example-one,NAMESERVER_RESTRICTED,"
|
||||
+ "ns2.example.net:ns3.example.net:ns4.example.net"))
|
||||
.setAllowedFullyQualifiedHostNames(
|
||||
ImmutableSet.of("ns1.example.net", "ns2.example.net", "ns3.example.net"))
|
||||
.build());
|
||||
NameserversNotAllowedForDomainException thrown =
|
||||
assertThrows(NameserversNotAllowedForDomainException.class, this::runFlowAsSuperuser);
|
||||
assertThat(thrown).hasMessageThat().contains("ns1.example.net");
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_domainNameserversAllowed_tldNameserversDisallowed() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setReservedLists(
|
||||
persistReservedList(
|
||||
"reserved",
|
||||
"example-one,NAMESERVER_RESTRICTED,"
|
||||
+ "ns2.example.net:ns3.example.net:ns1.example.net"))
|
||||
.setAllowedFullyQualifiedHostNames(
|
||||
ImmutableSet.of("ns4.example.net", "ns2.example.net", "ns3.example.net"))
|
||||
.build());
|
||||
NameserversNotAllowedForTldException thrown =
|
||||
assertThrows(NameserversNotAllowedForTldException.class, this::runFlowAsSuperuser);
|
||||
assertThat(thrown).hasMessageThat().contains("ns1.example.net");
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_sunrushAddGracePeriod() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
setEppInput("domain_allocate_no_nameservers.xml");
|
||||
doSuccessfulTest(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_nonDefaultAddGracePeriod() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setAddGracePeriodLength(Duration.standardMinutes(6))
|
||||
.build());
|
||||
doSuccessfulTest(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_nonDefaultSunrushAddGracePeriod() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setSunrushAddGracePeriodLength(Duration.standardMinutes(9))
|
||||
.build());
|
||||
doSuccessfulTest(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_existedButWasDeleted() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
persistDeletedDomain(getUniqueIdFromCommand(), clock.nowUtc().minusDays(1));
|
||||
clock.advanceOneMilli();
|
||||
doSuccessfulTest(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_maxNumberOfNameservers() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
setEppInput("domain_allocate_13_nameservers.xml");
|
||||
doSuccessfulTest(13);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_secDns() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
setEppInput("domain_allocate_dsdata.xml");
|
||||
doSuccessfulTest(2);
|
||||
assertAboutDomains()
|
||||
.that(reloadResourceByForeignKey())
|
||||
.hasExactlyDsData(
|
||||
DelegationSignerData.create(12345, 3, 1, base16().decode("49FD46E6C4B45C55D4AC")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_secDnsMaxRecords() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
setEppInput("domain_allocate_dsdata_8_records.xml");
|
||||
doSuccessfulTest(2);
|
||||
assertThat(getOnlyGlobalResource(DomainResource.class)).isNotNull();
|
||||
assertThat(reloadResourceByForeignKey().getDsData()).hasSize(8);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_idn() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
setEppInput("domain_allocate_idn.xml");
|
||||
clock.advanceOneMilli();
|
||||
runFlowAsSuperuser();
|
||||
assertThat(getOnlyGlobalResource(DomainResource.class)).isNotNull();
|
||||
assertDnsTasksEnqueued("xn--abc-873b2e7eb1k8a4lpjvv.tld");
|
||||
}
|
||||
|
||||
private void doSuccessfulClaimsNoticeTest() throws Exception {
|
||||
setEppInput("domain_allocate_claims_notice.xml");
|
||||
runFlowAsSuperuser();
|
||||
assertAboutDomains()
|
||||
.that(getOnlyGlobalResource(DomainResource.class))
|
||||
.hasLaunchNotice(
|
||||
LaunchNotice.create(
|
||||
"370d0b7c9223372036854775807",
|
||||
"tmch",
|
||||
DateTime.parse("2011-08-16T09:00:00.0Z"),
|
||||
DateTime.parse("2010-07-16T09:00:00.0Z")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_claimsNotice() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
doSuccessfulClaimsNoticeTest();
|
||||
String expectedCsv =
|
||||
String.format(
|
||||
"%s,example-one.tld,370d0b7c9223372036854775807,1,"
|
||||
+ "2010-09-16T10:00:00.000Z,2010-07-16T09:00:00.000Z,2010-08-16T10:00:00.000Z",
|
||||
reloadResourceByForeignKey().getRepoId());
|
||||
assertTasksEnqueued("lordn-claims", new TaskMatcher().payload(expectedCsv).tag("tld"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_expiredClaim() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
clock.setTo(DateTime.parse("2011-08-17T09:00:00.0Z"));
|
||||
doSuccessfulClaimsNoticeTest();
|
||||
String expectedCsv =
|
||||
String.format(
|
||||
"%s,example-one.tld,370d0b7c9223372036854775807,1,"
|
||||
+ "2011-08-17T09:00:00.000Z,2010-07-16T09:00:00.000Z,2010-08-16T10:00:00.000Z",
|
||||
reloadResourceByForeignKey().getRepoId());
|
||||
assertTasksEnqueued("lordn-claims", new TaskMatcher().payload(expectedCsv).tag("tld"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_smdId() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
setEppInput("domain_allocate_smd_id.xml");
|
||||
doSuccessfulTest(2);
|
||||
DomainResource domain = getOnlyGlobalResource(DomainResource.class);
|
||||
assertThat(domain.getSmdId()).isEqualTo(SMD_ID);
|
||||
String expectedCsv =
|
||||
String.format(
|
||||
"%s,example-one.tld,1-1,1,2010-09-16T10:00:00.000Z,2010-08-16T10:00:00.000Z",
|
||||
domain.getRepoId());
|
||||
assertTasksEnqueued("lordn-sunrise", new TaskMatcher().payload(expectedCsv).tag("tld"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_collision() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
setEppInput("domain_allocate_collision.xml");
|
||||
assertNoDnsTasksEnqueued();
|
||||
runFlowAsSuperuser();
|
||||
assertAboutDomains()
|
||||
.that(getOnlyGlobalResource(DomainResource.class))
|
||||
.hasStatusValue(StatusValue.SERVER_HOLD);
|
||||
assertNoDnsTasksEnqueued();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_reserved() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
setEppInput("domain_allocate_reserved.xml");
|
||||
runFlowAsSuperuser();
|
||||
assertThat(getOnlyGlobalResource(DomainResource.class)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_premiumName() throws Exception {
|
||||
setEppInput("domain_allocate_premium.xml");
|
||||
setupDomainApplication("example", TldState.QUIET_PERIOD);
|
||||
persistResource(Registry.get("example").asBuilder().setPremiumPriceAckRequired(true).build());
|
||||
clock.advanceOneMilli();
|
||||
runFlowAsSuperuser();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_hexApplicationId() throws Exception {
|
||||
setEppInput(
|
||||
"domain_allocate.xml",
|
||||
ImmutableMap.of("APPLICATIONID", "A-TLD", "DOMAIN", "example-one.tld"));
|
||||
applicationId = "A-TLD";
|
||||
// Grab the next 8 ids so that when the application is created it gets dec 10, or hex A.
|
||||
// (one additional ID goes to the reserved list created before the application).
|
||||
for (int i = 1; i <= 8; i++) {
|
||||
ObjectifyService.allocateId();
|
||||
}
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
doSuccessfulTest(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_expiredAcceptance() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
doSuccessfulClaimsNoticeTest();
|
||||
assertNoTasksEnqueued("lordn-sunrise");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_missingClaimsNotice() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
persistClaimsList(
|
||||
ImmutableMap.of("example-one", "2013041500/2/6/9/rJ1NrDO92vDsAzf7EQzgjX4R0000000001"));
|
||||
doSuccessfulTest(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_alreadyExists() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
persistActiveDomain(getUniqueIdFromCommand());
|
||||
EppException thrown =
|
||||
assertThrows(ResourceAlreadyExistsException.class, this::runFlowAsSuperuser);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_predelegation() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
createTld("tld", TldState.PREDELEGATION);
|
||||
doSuccessfulTest(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_sunrise() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
createTld("tld", TldState.SUNRISE);
|
||||
doSuccessfulTest(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_sunrush() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
createTld("tld", TldState.SUNRUSH);
|
||||
doSuccessfulTest(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_quietPeriod() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
createTld("tld", TldState.QUIET_PERIOD);
|
||||
doSuccessfulTest(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_applicationDeleted() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
persistResource(application.asBuilder().setDeletionTime(clock.nowUtc()).build());
|
||||
EppException thrown = assertThrows(MissingApplicationException.class, this::runFlowAsSuperuser);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_applicationRejected() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
persistResource(
|
||||
application.asBuilder().setApplicationStatus(ApplicationStatus.REJECTED).build());
|
||||
EppException thrown = assertThrows(HasFinalStatusException.class, this::runFlowAsSuperuser);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_applicationAllocated() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
persistResource(
|
||||
application.asBuilder().setApplicationStatus(ApplicationStatus.ALLOCATED).build());
|
||||
EppException thrown = assertThrows(HasFinalStatusException.class, this::runFlowAsSuperuser);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_applicationDoesNotExist() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
setEppInput("domain_allocate_bad_application_roid.xml");
|
||||
EppException thrown = assertThrows(MissingApplicationException.class, this::runFlowAsSuperuser);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_onlySuperuserCanAllocate() throws Exception {
|
||||
setupDomainApplication("tld", TldState.GENERAL_AVAILABILITY);
|
||||
clock.advanceOneMilli();
|
||||
setEppInput("domain_allocate_no_nameservers.xml");
|
||||
assertTransactionalFlow(true);
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
OnlySuperuserCanAllocateException.class,
|
||||
() -> runFlow(CommitMode.LIVE, UserPrivileges.NORMAL));
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_max10Years() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
setEppInput("domain_allocate_11_years.xml");
|
||||
EppException thrown =
|
||||
assertThrows(ExceedsMaxRegistrationYearsException.class, this::runFlowAsSuperuser);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
runFlow(CommitMode.LIVE, UserPrivileges.SUPERUSER);
|
||||
assertIcannReportingActivityFieldLogged("srs-dom-create");
|
||||
assertTldsFieldLogged("tld");
|
||||
// Ensure we log the client ID for srs-dom-create so we can also use it for attempted-adds.
|
||||
assertClientIdFieldLogged("TheRegistrar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIcannTransactionRecord_getsStored() throws Exception {
|
||||
setupDomainApplication("tld", TldState.QUIET_PERIOD);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setRenewGracePeriodLength(Duration.standardMinutes(9))
|
||||
.build());
|
||||
runFlow(CommitMode.LIVE, UserPrivileges.SUPERUSER);
|
||||
DomainResource domain = reloadResourceByForeignKey();
|
||||
HistoryEntry historyEntry =
|
||||
getOnlyHistoryEntryOfType(domain, HistoryEntry.Type.DOMAIN_ALLOCATE);
|
||||
assertThat(historyEntry.getDomainTransactionRecords())
|
||||
.containsExactly(
|
||||
DomainTransactionRecord.create(
|
||||
"tld",
|
||||
historyEntry.getModificationTime().plusMinutes(9),
|
||||
TransactionReportField.netAddsFieldFromYears(2),
|
||||
1));
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,345 +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.flows.domain;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth8.assertThat;
|
||||
import static google.registry.model.EppResourceUtils.isLinked;
|
||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
||||
import static google.registry.model.EppResourceUtils.loadDomainApplication;
|
||||
import static google.registry.model.index.ForeignKeyIndex.loadAndGetKey;
|
||||
import static google.registry.testing.DatastoreHelper.assertNoBillingEvents;
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
import static google.registry.testing.DatastoreHelper.loadRegistrar;
|
||||
import static google.registry.testing.DatastoreHelper.newDomainApplication;
|
||||
import static google.registry.testing.DatastoreHelper.newHostResource;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveContact;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveDomainApplication;
|
||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions;
|
||||
import static google.registry.testing.JUnitBackports.assertThrows;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppException.UnimplementedExtensionException;
|
||||
import google.registry.flows.ResourceFlowTestCase;
|
||||
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
|
||||
import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
|
||||
import google.registry.flows.domain.DomainApplicationDeleteFlow.SunriseApplicationCannotBeDeletedInLandrushException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.ApplicationDomainNameMismatchException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.BadCommandForRegistryPhaseException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.LaunchPhaseMismatchException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException;
|
||||
import google.registry.model.EppResource;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
import google.registry.model.domain.launch.LaunchPhase;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.host.HostResource;
|
||||
import google.registry.model.registry.Registry.TldState;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/** Unit tests for {@link DomainApplicationDeleteFlow}. */
|
||||
public class DomainApplicationDeleteFlowTest
|
||||
extends ResourceFlowTestCase<DomainApplicationDeleteFlow, DomainApplication> {
|
||||
|
||||
public DomainApplicationDeleteFlowTest() {
|
||||
setEppInput("domain_delete_application.xml");
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
createTld("tld", TldState.SUNRUSH);
|
||||
createTld("extra", TldState.LANDRUSH);
|
||||
}
|
||||
|
||||
public void doSuccessfulTest() throws Exception {
|
||||
assertTransactionalFlow(true);
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(loadFile("generic_success_response.xml"));
|
||||
// Check that the domain is fully deleted.
|
||||
assertThat(loadDomainApplication(getUniqueIdFromCommand(), clock.nowUtc())).isEmpty();
|
||||
assertNoBillingEvents();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDryRun() throws Exception {
|
||||
persistResource(newDomainApplication("example.tld").asBuilder().setRepoId("1-TLD").build());
|
||||
dryRunFlowAssertResponse(loadFile("generic_success_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_contactsAndHostUnlinked() throws Exception {
|
||||
// Persist a linked contact and host
|
||||
persistActiveContact("sh8013");
|
||||
persistResource(newHostResource("ns1.example.net"));
|
||||
// Create the DomainApplication to test.
|
||||
persistResource(
|
||||
newDomainApplication("example.tld")
|
||||
.asBuilder()
|
||||
.setRepoId("1-TLD")
|
||||
.setRegistrant(
|
||||
Key.create(loadByForeignKey(ContactResource.class, "sh8013", clock.nowUtc()).get()))
|
||||
.setNameservers(
|
||||
Key.create(
|
||||
loadByForeignKey(HostResource.class, "ns1.example.net", clock.nowUtc()).get()))
|
||||
.build());
|
||||
doSuccessfulTest();
|
||||
for (Key<? extends EppResource> key :
|
||||
ImmutableList.of(
|
||||
loadAndGetKey(ContactResource.class, "sh8013", clock.nowUtc()),
|
||||
loadAndGetKey(HostResource.class, "ns1.example.net", clock.nowUtc()))) {
|
||||
assertThat(isLinked(key, clock.nowUtc())).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_clientDeleteProhibited() throws Exception {
|
||||
persistResource(
|
||||
newDomainApplication("example.tld")
|
||||
.asBuilder()
|
||||
.setRepoId("1-TLD")
|
||||
.addStatusValue(StatusValue.CLIENT_DELETE_PROHIBITED)
|
||||
.build());
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_serverDeleteProhibited() throws Exception {
|
||||
persistResource(
|
||||
newDomainApplication("example.tld")
|
||||
.asBuilder()
|
||||
.setRepoId("1-TLD")
|
||||
.addStatusValue(StatusValue.SERVER_DELETE_PROHIBITED)
|
||||
.build());
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_neverExisted() throws Exception {
|
||||
ResourceDoesNotExistException thrown =
|
||||
assertThrows(ResourceDoesNotExistException.class, this::runFlow);
|
||||
assertThat(thrown).hasMessageThat().contains(String.format("(%s)", getUniqueIdFromCommand()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_existedButWasDeleted() throws Exception {
|
||||
persistResource(
|
||||
newDomainApplication("example.tld")
|
||||
.asBuilder()
|
||||
.setRepoId("1-TLD")
|
||||
.setDeletionTime(clock.nowUtc().minusSeconds(1))
|
||||
.build());
|
||||
ResourceDoesNotExistException thrown =
|
||||
assertThrows(ResourceDoesNotExistException.class, this::runFlow);
|
||||
assertThat(thrown).hasMessageThat().contains(String.format("(%s)", getUniqueIdFromCommand()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unauthorizedClient() {
|
||||
sessionMetadata.setClientId("NewRegistrar");
|
||||
persistResource(newDomainApplication("example.tld").asBuilder().setRepoId("1-TLD").build());
|
||||
EppException thrown = assertThrows(ResourceNotOwnedException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_superuserUnauthorizedClient() throws Exception {
|
||||
sessionMetadata.setClientId("NewRegistrar");
|
||||
persistResource(newDomainApplication("example.tld").asBuilder().setRepoId("1-TLD").build());
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(
|
||||
CommitMode.LIVE, UserPrivileges.SUPERUSER, loadFile("generic_success_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_notAuthorizedForTld() {
|
||||
persistResource(newDomainApplication("example.tld").asBuilder().setRepoId("1-TLD").build());
|
||||
persistResource(
|
||||
loadRegistrar("TheRegistrar").asBuilder().setAllowedTlds(ImmutableSet.of()).build());
|
||||
EppException thrown = assertThrows(NotAuthorizedForTldException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_superuserNotAuthorizedForTld() throws Exception {
|
||||
persistResource(newDomainApplication("example.tld").asBuilder().setRepoId("1-TLD").build());
|
||||
persistResource(
|
||||
loadRegistrar("TheRegistrar").asBuilder().setAllowedTlds(ImmutableSet.of()).build());
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(
|
||||
CommitMode.LIVE, UserPrivileges.SUPERUSER, loadFile("generic_success_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_sunriseDuringLandrush() {
|
||||
createTld("tld", TldState.LANDRUSH);
|
||||
setEppInput("domain_delete_application_landrush.xml", ImmutableMap.of("DOMAIN", "example.tld"));
|
||||
persistResource(
|
||||
newDomainApplication("example.tld")
|
||||
.asBuilder()
|
||||
.setRepoId("1-TLD")
|
||||
.setPhase(LaunchPhase.SUNRISE)
|
||||
.build());
|
||||
EppException thrown =
|
||||
assertThrows(SunriseApplicationCannotBeDeletedInLandrushException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_superuserSunriseDuringLandrush() throws Exception {
|
||||
createTld("tld", TldState.LANDRUSH);
|
||||
setEppInput("domain_delete_application_landrush.xml", ImmutableMap.of("DOMAIN", "example.tld"));
|
||||
persistResource(
|
||||
newDomainApplication("example.tld")
|
||||
.asBuilder()
|
||||
.setRepoId("1-TLD")
|
||||
.setPhase(LaunchPhase.SUNRISE)
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(
|
||||
CommitMode.LIVE, UserPrivileges.SUPERUSER, loadFile("generic_success_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_sunrushDuringLandrush() throws Exception {
|
||||
createTld("tld", TldState.LANDRUSH);
|
||||
setEppInput("domain_delete_application_landrush.xml", ImmutableMap.of("DOMAIN", "example.tld"));
|
||||
persistResource(
|
||||
newDomainApplication("example.tld")
|
||||
.asBuilder()
|
||||
.setRepoId("1-TLD")
|
||||
.setPhase(LaunchPhase.SUNRUSH)
|
||||
.build());
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_sunriseDuringSunrush() throws Exception {
|
||||
createTld("tld", TldState.SUNRUSH);
|
||||
setEppInput("domain_delete_application_sunrush.xml");
|
||||
persistResource(
|
||||
newDomainApplication("example.tld")
|
||||
.asBuilder()
|
||||
.setRepoId("1-TLD")
|
||||
.setPhase(LaunchPhase.SUNRISE)
|
||||
.build());
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_mismatchedPhase() {
|
||||
setEppInput("domain_delete_application_landrush.xml", ImmutableMap.of("DOMAIN", "example.tld"));
|
||||
persistResource(newDomainApplication("example.tld").asBuilder().setRepoId("1-TLD").build());
|
||||
EppException thrown = assertThrows(LaunchPhaseMismatchException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_wrongExtension() {
|
||||
setEppInput("domain_delete_application_wrong_extension.xml");
|
||||
persistActiveDomainApplication("example.tld");
|
||||
EppException thrown = assertThrows(UnimplementedExtensionException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_predelegation() {
|
||||
createTld("tld", TldState.PREDELEGATION);
|
||||
persistResource(newDomainApplication("example.tld").asBuilder().setRepoId("1-TLD").build());
|
||||
EppException thrown = assertThrows(BadCommandForRegistryPhaseException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_quietPeriod() {
|
||||
createTld("tld", TldState.QUIET_PERIOD);
|
||||
persistResource(newDomainApplication("example.tld").asBuilder().setRepoId("1-TLD").build());
|
||||
EppException thrown = assertThrows(BadCommandForRegistryPhaseException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_generalAvailability() {
|
||||
createTld("tld", TldState.GENERAL_AVAILABILITY);
|
||||
persistResource(newDomainApplication("example.tld").asBuilder().setRepoId("1-TLD").build());
|
||||
EppException thrown = assertThrows(BadCommandForRegistryPhaseException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_startDateSunrise() {
|
||||
createTld("tld", TldState.START_DATE_SUNRISE);
|
||||
persistResource(newDomainApplication("example.tld").asBuilder().setRepoId("1-TLD").build());
|
||||
EppException thrown = assertThrows(BadCommandForRegistryPhaseException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_superuserQuietPeriod() throws Exception {
|
||||
createTld("tld", TldState.QUIET_PERIOD);
|
||||
persistResource(newDomainApplication("example.tld").asBuilder().setRepoId("1-TLD").build());
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(
|
||||
CommitMode.LIVE, UserPrivileges.SUPERUSER, loadFile("generic_success_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_superuserPredelegation() throws Exception {
|
||||
createTld("tld", TldState.PREDELEGATION);
|
||||
persistResource(newDomainApplication("example.tld").asBuilder().setRepoId("1-TLD").build());
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(
|
||||
CommitMode.LIVE, UserPrivileges.SUPERUSER, loadFile("generic_success_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_superuserGeneralAvailability() throws Exception {
|
||||
createTld("tld", TldState.GENERAL_AVAILABILITY);
|
||||
persistResource(newDomainApplication("example.tld").asBuilder().setRepoId("1-TLD").build());
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(
|
||||
CommitMode.LIVE, UserPrivileges.SUPERUSER, loadFile("generic_success_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_superuserStartDateSunrise() throws Exception {
|
||||
createTld("tld", TldState.START_DATE_SUNRISE);
|
||||
persistResource(newDomainApplication("example.tld").asBuilder().setRepoId("1-TLD").build());
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(
|
||||
CommitMode.LIVE, UserPrivileges.SUPERUSER, loadFile("generic_success_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_applicationIdForDifferentDomain() {
|
||||
persistResource(newDomainApplication("invalid.tld").asBuilder().setRepoId("1-TLD").build());
|
||||
EppException thrown = assertThrows(ApplicationDomainNameMismatchException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
persistResource(newDomainApplication("example.tld").asBuilder().setRepoId("1-TLD").build());
|
||||
clock.advanceOneMilli();
|
||||
runFlow();
|
||||
assertIcannReportingActivityFieldLogged("srs-dom-delete");
|
||||
assertTldsFieldLogged("tld");
|
||||
}
|
||||
}
|
|
@ -1,380 +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.flows.domain;
|
||||
|
||||
import static com.google.common.io.BaseEncoding.base16;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.testing.DatastoreHelper.assertNoBillingEvents;
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveContact;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveHost;
|
||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions;
|
||||
import static google.registry.testing.JUnitBackports.assertThrows;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.ResourceFlowTestCase;
|
||||
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
|
||||
import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
|
||||
import google.registry.flows.domain.DomainApplicationInfoFlow.ApplicationLaunchPhaseMismatchException;
|
||||
import google.registry.flows.domain.DomainApplicationInfoFlow.MissingApplicationIdException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.ApplicationDomainNameMismatchException;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.domain.DesignatedContact;
|
||||
import google.registry.model.domain.DesignatedContact.Type;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
import google.registry.model.domain.DomainAuthInfo;
|
||||
import google.registry.model.domain.launch.ApplicationStatus;
|
||||
import google.registry.model.domain.launch.LaunchCreateExtension;
|
||||
import google.registry.model.domain.launch.LaunchPhase;
|
||||
import google.registry.model.domain.secdns.DelegationSignerData;
|
||||
import google.registry.model.eppcommon.AuthInfo.PasswordAuth;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.host.HostResource;
|
||||
import google.registry.model.ofy.RequestCapturingAsyncDatastoreService;
|
||||
import google.registry.model.registry.Registry.TldState;
|
||||
import google.registry.model.smd.EncodedSignedMark;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.EppLoader;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/** Unit tests for {@link DomainApplicationInfoFlow}. */
|
||||
public class DomainApplicationInfoFlowTest
|
||||
extends ResourceFlowTestCase<DomainApplicationInfoFlow, DomainApplication> {
|
||||
|
||||
private ContactResource registrant;
|
||||
private ContactResource contact;
|
||||
private HostResource host1;
|
||||
private HostResource host2;
|
||||
private DomainApplication application;
|
||||
|
||||
private enum MarksState {
|
||||
MARKS_EXIST,
|
||||
NO_MARKS_EXIST
|
||||
}
|
||||
|
||||
private enum HostsState {
|
||||
HOSTS_EXIST,
|
||||
NO_HOSTS_EXIST
|
||||
}
|
||||
|
||||
@Before
|
||||
public void resetClientId() {
|
||||
setEppInput("domain_info_sunrise.xml");
|
||||
sessionMetadata.setClientId("NewRegistrar");
|
||||
createTld("tld", TldState.SUNRUSH);
|
||||
}
|
||||
|
||||
private void persistTestEntities(HostsState hostsState, MarksState marksState) throws Exception {
|
||||
registrant = persistActiveContact("jd1234");
|
||||
contact = persistActiveContact("sh8013");
|
||||
host1 = persistActiveHost("ns1.example.net");
|
||||
host2 = persistActiveHost("ns1.example.tld");
|
||||
application =
|
||||
persistResource(
|
||||
new DomainApplication.Builder()
|
||||
.setRepoId("123-TLD")
|
||||
.setFullyQualifiedDomainName("example.tld")
|
||||
.setPhase(LaunchPhase.SUNRUSH)
|
||||
.setPersistedCurrentSponsorClientId("NewRegistrar")
|
||||
.setCreationClientId("TheRegistrar")
|
||||
.setLastEppUpdateClientId("NewRegistrar")
|
||||
.setCreationTimeForTest(DateTime.parse("1999-04-03T22:00:00.0Z"))
|
||||
.setLastEppUpdateTime(DateTime.parse("1999-12-03T09:00:00.0Z"))
|
||||
.setRegistrant(Key.create(registrant))
|
||||
.setContacts(
|
||||
ImmutableSet.of(
|
||||
DesignatedContact.create(Type.ADMIN, Key.create(contact)),
|
||||
DesignatedContact.create(Type.TECH, Key.create(contact))))
|
||||
.setNameservers(
|
||||
hostsState.equals(HostsState.HOSTS_EXIST)
|
||||
? ImmutableSet.of(Key.create(host1), Key.create(host2))
|
||||
: null)
|
||||
.setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("2fooBAR")))
|
||||
.addStatusValue(StatusValue.PENDING_CREATE)
|
||||
.setApplicationStatus(ApplicationStatus.PENDING_VALIDATION)
|
||||
.setEncodedSignedMarks(
|
||||
marksState.equals(MarksState.MARKS_EXIST)
|
||||
// If we need to include an encoded signed mark, pull it out of the create
|
||||
// xml.
|
||||
? ImmutableList.of(
|
||||
(EncodedSignedMark)
|
||||
new EppLoader(this, "domain_create_sunrise_encoded_signed_mark.xml")
|
||||
.getEpp()
|
||||
.getSingleExtension(LaunchCreateExtension.class)
|
||||
.get()
|
||||
.getSignedMarks()
|
||||
.get(0))
|
||||
: null)
|
||||
.build());
|
||||
}
|
||||
|
||||
private void doSuccessfulTest(String expectedXmlFilename, HostsState hostsState)
|
||||
throws Exception {
|
||||
assertTransactionalFlow(false);
|
||||
String expected = loadFile(expectedXmlFilename, ImmutableMap.of("ROID", "123-TLD"));
|
||||
if (hostsState.equals(HostsState.NO_HOSTS_EXIST)) {
|
||||
expected = expected.replaceAll("\"ok\"", "\"inactive\"");
|
||||
}
|
||||
runFlowAssertResponse(expected);
|
||||
assertNoHistory();
|
||||
assertNoBillingEvents();
|
||||
}
|
||||
|
||||
private void doSuccessfulTest(String expectedXmlFilename) throws Exception {
|
||||
persistTestEntities(HostsState.HOSTS_EXIST, MarksState.NO_MARKS_EXIST);
|
||||
doSuccessfulTest(expectedXmlFilename, HostsState.HOSTS_EXIST);
|
||||
}
|
||||
|
||||
private void doSuccessfulTestNoNameservers(String expectedXmlFilename) throws Exception {
|
||||
persistTestEntities(HostsState.NO_HOSTS_EXIST, MarksState.NO_MARKS_EXIST);
|
||||
doSuccessfulTest(expectedXmlFilename, HostsState.NO_HOSTS_EXIST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_quietPeriod() throws Exception {
|
||||
createTld("tld", TldState.QUIET_PERIOD);
|
||||
doSuccessfulTest("domain_info_sunrise_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_generalAvailability() throws Exception {
|
||||
createTld("tld", TldState.GENERAL_AVAILABILITY);
|
||||
doSuccessfulTest("domain_info_sunrise_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_requestedDefaultHosts_nameserversExist() throws Exception {
|
||||
// Default is "all", which means nameservers since there can't be subordinates.
|
||||
doSuccessfulTest("domain_info_sunrise_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_requestedDefaultHosts_noNameserversExist() throws Exception {
|
||||
// Default is "all", which means nameservers since there can't be subordinates.
|
||||
doSuccessfulTestNoNameservers("domain_info_sunrise_response_no_nameservers.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_requestedAllHosts_nameserversExist() throws Exception {
|
||||
// "All" means nameservers since there can't be subordinates (same as "delegated").
|
||||
setEppInput("domain_info_sunrise_all_hosts.xml");
|
||||
doSuccessfulTest("domain_info_sunrise_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_requestedAllHosts_noNameserversExist() throws Exception {
|
||||
// "All" means nameservers since there can't be subordinates (same as "delegated").
|
||||
setEppInput("domain_info_sunrise_all_hosts.xml");
|
||||
doSuccessfulTestNoNameservers("domain_info_sunrise_response_no_nameservers.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_requestedDelegatedHosts_nameserversExist() throws Exception {
|
||||
// "Delegated" means nameservers since there can't be subordinates (same as "all").
|
||||
setEppInput("domain_info_sunrise_delegated_hosts.xml");
|
||||
doSuccessfulTest("domain_info_sunrise_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_requestedDelegatedHosts_noNameserversExist() throws Exception {
|
||||
// "Delegated" means nameservers since there can't be subordinates (same as "all").
|
||||
setEppInput("domain_info_sunrise_delegated_hosts.xml");
|
||||
doSuccessfulTestNoNameservers("domain_info_sunrise_response_no_nameservers.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_requestedNoneHosts_nameserversExist() throws Exception {
|
||||
setEppInput("domain_info_sunrise_none_hosts.xml");
|
||||
doSuccessfulTestNoNameservers("domain_info_sunrise_response_no_nameservers.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_requestedNoneHosts_noNameserversExist() throws Exception {
|
||||
setEppInput("domain_info_sunrise_none_hosts.xml");
|
||||
doSuccessfulTestNoNameservers("domain_info_sunrise_response_no_nameservers.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_requestedDefaultMarks_noMarksExist() throws Exception {
|
||||
persistTestEntities(HostsState.HOSTS_EXIST, MarksState.NO_MARKS_EXIST);
|
||||
doSuccessfulTest("domain_info_sunrise_response.xml", HostsState.HOSTS_EXIST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_requestedDefaultMarks_marksExist() throws Exception {
|
||||
persistTestEntities(HostsState.HOSTS_EXIST, MarksState.MARKS_EXIST);
|
||||
doSuccessfulTest("domain_info_sunrise_response.xml", HostsState.HOSTS_EXIST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_requestedNoMarks_marksExist() throws Exception {
|
||||
setEppInput("domain_info_sunrise_no_marks.xml");
|
||||
persistTestEntities(HostsState.HOSTS_EXIST, MarksState.MARKS_EXIST);
|
||||
doSuccessfulTest("domain_info_sunrise_response.xml", HostsState.HOSTS_EXIST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_requestedNoMarks_noMarksExist() throws Exception {
|
||||
setEppInput("domain_info_sunrise_no_marks.xml");
|
||||
persistTestEntities(HostsState.HOSTS_EXIST, MarksState.NO_MARKS_EXIST);
|
||||
doSuccessfulTest("domain_info_sunrise_response.xml", HostsState.HOSTS_EXIST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_requestedIncludeMarks_marksExist() throws Exception {
|
||||
setEppInput("domain_info_sunrise_include_marks.xml");
|
||||
persistTestEntities(HostsState.HOSTS_EXIST, MarksState.MARKS_EXIST);
|
||||
doSuccessfulTest("domain_info_sunrise_response_with_mark.xml", HostsState.HOSTS_EXIST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_requestedIncludeMarks_noMarksExist() throws Exception {
|
||||
setEppInput("domain_info_sunrise_include_marks.xml");
|
||||
persistTestEntities(HostsState.HOSTS_EXIST, MarksState.NO_MARKS_EXIST);
|
||||
doSuccessfulTest("domain_info_sunrise_response.xml", HostsState.HOSTS_EXIST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_secDns() throws Exception {
|
||||
persistTestEntities(HostsState.NO_HOSTS_EXIST, MarksState.NO_MARKS_EXIST);
|
||||
// Add the dsData to the saved resource and change the nameservers to match the sample xml.
|
||||
persistResource(
|
||||
application
|
||||
.asBuilder()
|
||||
.setDsData(
|
||||
ImmutableSet.of(
|
||||
DelegationSignerData.create(
|
||||
12345, 3, 1, base16().decode("49FD46E6C4B45C55D4AC"))))
|
||||
.setNameservers(ImmutableSet.of(Key.create(host1), Key.create(host2)))
|
||||
.build());
|
||||
doSuccessfulTest("domain_info_sunrise_response_dsdata.xml", HostsState.NO_HOSTS_EXIST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_allocated() throws Exception {
|
||||
persistTestEntities(HostsState.HOSTS_EXIST, MarksState.NO_MARKS_EXIST);
|
||||
// Update the application status of the saved resource.
|
||||
persistResource(
|
||||
application
|
||||
.asBuilder()
|
||||
.removeStatusValue(StatusValue.PENDING_CREATE)
|
||||
.setApplicationStatus(ApplicationStatus.ALLOCATED)
|
||||
.build());
|
||||
doSuccessfulTest("domain_info_sunrise_allocated.xml", HostsState.HOSTS_EXIST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_neverExisted() throws Exception {
|
||||
ResourceDoesNotExistException thrown =
|
||||
assertThrows(ResourceDoesNotExistException.class, this::runFlow);
|
||||
assertThat(thrown).hasMessageThat().contains(String.format("(%s)", getUniqueIdFromCommand()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_existedButWasDeleted() throws Exception {
|
||||
persistResource(
|
||||
new DomainApplication.Builder()
|
||||
.setRepoId("123-COM")
|
||||
.setFullyQualifiedDomainName("timber.com")
|
||||
.setDeletionTime(clock.nowUtc().minusDays(1))
|
||||
.setRegistrant(Key.create(persistActiveContact("jd1234")))
|
||||
.build());
|
||||
ResourceDoesNotExistException thrown =
|
||||
assertThrows(ResourceDoesNotExistException.class, this::runFlow);
|
||||
assertThat(thrown).hasMessageThat().contains(String.format("(%s)", getUniqueIdFromCommand()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unauthorized() throws Exception {
|
||||
persistResource(AppEngineRule.makeRegistrar1().asBuilder().setClientId("ClientZ").build());
|
||||
sessionMetadata.setClientId("ClientZ");
|
||||
persistTestEntities(HostsState.NO_HOSTS_EXIST, MarksState.NO_MARKS_EXIST);
|
||||
EppException thrown = assertThrows(ResourceNotOwnedException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_applicationIdForDifferentDomain() {
|
||||
persistResource(
|
||||
new DomainApplication.Builder()
|
||||
.setRepoId("123-TLD")
|
||||
.setFullyQualifiedDomainName("invalid.tld")
|
||||
.setRegistrant(Key.create(persistActiveContact("jd1234")))
|
||||
.setPhase(LaunchPhase.SUNRUSH)
|
||||
.build());
|
||||
EppException thrown = assertThrows(ApplicationDomainNameMismatchException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_noApplicationId() throws Exception {
|
||||
setEppInput("domain_info_sunrise_no_application_id.xml");
|
||||
persistTestEntities(HostsState.NO_HOSTS_EXIST, MarksState.NO_MARKS_EXIST);
|
||||
EppException thrown = assertThrows(MissingApplicationIdException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_mismatchedLaunchPhase() throws Exception {
|
||||
persistTestEntities(HostsState.NO_HOSTS_EXIST, MarksState.NO_MARKS_EXIST);
|
||||
application = persistResource(application.asBuilder().setPhase(LaunchPhase.SUNRISE).build());
|
||||
EppException thrown =
|
||||
assertThrows(ApplicationLaunchPhaseMismatchException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
/** Test that we load contacts and hosts as a batch rather than individually. */
|
||||
@Test
|
||||
public void testBatchLoadingOfReferences() throws Exception {
|
||||
persistTestEntities(HostsState.HOSTS_EXIST, MarksState.NO_MARKS_EXIST);
|
||||
// Clear out the session cache so that we count actual Datastore calls.
|
||||
ofy().clearSessionCache();
|
||||
int numPreviousReads = RequestCapturingAsyncDatastoreService.getReads().size();
|
||||
doSuccessfulTest("domain_info_sunrise_response.xml", HostsState.HOSTS_EXIST);
|
||||
// Get all of the keys loaded in the flow, with each distinct load() call as a list of keys.
|
||||
long numReadsWithContactsOrHosts =
|
||||
RequestCapturingAsyncDatastoreService.getReads()
|
||||
.stream()
|
||||
.skip(numPreviousReads)
|
||||
.filter(
|
||||
keys ->
|
||||
keys.stream()
|
||||
.map(com.google.appengine.api.datastore.Key::getKind)
|
||||
.anyMatch(
|
||||
Predicates.in(
|
||||
ImmutableSet.of(
|
||||
Key.getKind(ContactResource.class),
|
||||
Key.getKind(HostResource.class)))))
|
||||
.count();
|
||||
assertThat(numReadsWithContactsOrHosts).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
persistTestEntities(HostsState.HOSTS_EXIST, MarksState.NO_MARKS_EXIST);
|
||||
runFlow();
|
||||
assertIcannReportingActivityFieldLogged("srs-dom-info");
|
||||
assertTldsFieldLogged("tld");
|
||||
}
|
||||
}
|
|
@ -1,932 +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.flows.domain;
|
||||
|
||||
import static com.google.common.collect.Sets.union;
|
||||
import static com.google.common.io.BaseEncoding.base16;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
||||
import static google.registry.testing.DatastoreHelper.assertNoBillingEvents;
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
import static google.registry.testing.DatastoreHelper.generateNewDomainRoid;
|
||||
import static google.registry.testing.DatastoreHelper.loadRegistrar;
|
||||
import static google.registry.testing.DatastoreHelper.newDomainApplication;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveContact;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveHost;
|
||||
import static google.registry.testing.DatastoreHelper.persistReservedList;
|
||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static google.registry.testing.DomainApplicationSubject.assertAboutApplications;
|
||||
import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions;
|
||||
import static google.registry.testing.JUnitBackports.assertThrows;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppException.UnimplementedExtensionException;
|
||||
import google.registry.flows.ResourceFlowTestCase;
|
||||
import google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException;
|
||||
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
|
||||
import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
|
||||
import google.registry.flows.ResourceFlowUtils.StatusNotClientSettableException;
|
||||
import google.registry.flows.domain.DomainApplicationUpdateFlow.ApplicationStatusProhibitsUpdateException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.ApplicationDomainNameMismatchException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.DuplicateContactForRoleException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.EmptySecDnsUpdateException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.FeesMismatchException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.LinkedResourcesDoNotExistException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.MaxSigLifeChangeNotSupportedException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.MissingAdminContactException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.MissingContactTypeException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.MissingTechnicalContactException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.NameserversNotAllowedForDomainException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.NameserversNotAllowedForTldException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.NameserversNotSpecifiedForNameserverRestrictedDomainException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.NameserversNotSpecifiedForTldWithNameserverWhitelistException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.RegistrantNotAllowedException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.SecDnsAllUsageException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.TooManyDsRecordsException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.TooManyNameserversException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.UrgentAttributeNotSupportedException;
|
||||
import google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException;
|
||||
import google.registry.flows.exceptions.ResourceStatusProhibitsOperationException;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.domain.DesignatedContact;
|
||||
import google.registry.model.domain.DesignatedContact.Type;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
import google.registry.model.domain.DomainApplication.Builder;
|
||||
import google.registry.model.domain.launch.ApplicationStatus;
|
||||
import google.registry.model.domain.secdns.DelegationSignerData;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.host.HostResource;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.model.registry.Registry.TldState;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/** Unit tests for {@link DomainApplicationUpdateFlow}. */
|
||||
public class DomainApplicationUpdateFlowTest
|
||||
extends ResourceFlowTestCase<DomainApplicationUpdateFlow, DomainApplication> {
|
||||
|
||||
private static final DelegationSignerData SOME_DSDATA =
|
||||
DelegationSignerData.create(1, 2, 3, new byte[] {0, 1, 2});
|
||||
|
||||
ContactResource sh8013Contact;
|
||||
ContactResource mak21Contact;
|
||||
ContactResource unusedContact;
|
||||
|
||||
public DomainApplicationUpdateFlowTest() {
|
||||
// Note that "domain_update_sunrise.xml" tests adding and removing the same contact type.
|
||||
setEppInput("domain_update_sunrise.xml");
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
createTld("tld", TldState.SUNRUSH);
|
||||
}
|
||||
|
||||
private void persistReferencedEntities() {
|
||||
// Grab the 1 id for use with the DomainApplication.
|
||||
generateNewDomainRoid("tld");
|
||||
for (int i = 1; i <= 14; ++i) {
|
||||
persistActiveHost(String.format("ns%d.example.tld", i));
|
||||
}
|
||||
sh8013Contact = persistActiveContact("sh8013");
|
||||
mak21Contact = persistActiveContact("mak21");
|
||||
unusedContact = persistActiveContact("unused");
|
||||
}
|
||||
|
||||
private DomainApplication persistApplication() {
|
||||
HostResource host =
|
||||
loadByForeignKey(HostResource.class, "ns1.example.tld", clock.nowUtc()).get();
|
||||
return persistResource(
|
||||
newApplicationBuilder()
|
||||
.setContacts(
|
||||
ImmutableSet.of(
|
||||
DesignatedContact.create(Type.TECH, Key.create(sh8013Contact)),
|
||||
DesignatedContact.create(Type.ADMIN, Key.create(unusedContact))))
|
||||
.setNameservers(ImmutableSet.of(Key.create(host)))
|
||||
.build());
|
||||
}
|
||||
|
||||
private Builder newApplicationBuilder() {
|
||||
return newDomainApplication("example.tld").asBuilder().setRepoId("1-TLD");
|
||||
}
|
||||
|
||||
private DomainApplication persistNewApplication() {
|
||||
return persistResource(newApplicationBuilder().build());
|
||||
}
|
||||
|
||||
private void doSuccessfulTest() throws Exception {
|
||||
assertTransactionalFlow(true);
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(loadFile("generic_success_response.xml"));
|
||||
// Check that the application was updated. These values came from the xml.
|
||||
DomainApplication application = reloadDomainApplication();
|
||||
assertAboutApplications()
|
||||
.that(application)
|
||||
.hasStatusValue(StatusValue.CLIENT_HOLD)
|
||||
.and()
|
||||
.hasOnlyOneHistoryEntryWhich()
|
||||
.hasType(HistoryEntry.Type.DOMAIN_APPLICATION_UPDATE);
|
||||
assertThat(application.getAuthInfo().getPw().getValue()).isEqualTo("2BARfoo");
|
||||
// Check that the hosts and contacts have correct linked status
|
||||
assertNoBillingEvents();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDryRun() throws Exception {
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
dryRunFlowAssertResponse(loadFile("generic_success_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception {
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_maxNumberOfNameservers() throws Exception {
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
modifyApplicationToHave13Nameservers();
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_removeContact() throws Exception {
|
||||
setEppInput("domain_update_sunrise_remove_contact.xml");
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_registrantMovedToTechContact() throws Exception {
|
||||
setEppInput("domain_update_sunrise_registrant_to_tech.xml");
|
||||
persistReferencedEntities();
|
||||
ContactResource sh8013 =
|
||||
loadByForeignKey(ContactResource.class, "sh8013", clock.nowUtc()).get();
|
||||
persistResource(newApplicationBuilder().setRegistrant(Key.create(sh8013)).build());
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(loadFile("generic_success_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_multipleReferencesToSameContactRemoved() throws Exception {
|
||||
setEppInput("domain_update_sunrise_remove_multiple_contacts.xml");
|
||||
persistReferencedEntities();
|
||||
ContactResource sh8013 =
|
||||
loadByForeignKey(ContactResource.class, "sh8013", clock.nowUtc()).get();
|
||||
Key<ContactResource> sh8013Key = Key.create(sh8013);
|
||||
persistResource(
|
||||
newApplicationBuilder()
|
||||
.setRegistrant(sh8013Key)
|
||||
.setContacts(
|
||||
ImmutableSet.of(
|
||||
DesignatedContact.create(Type.ADMIN, sh8013Key),
|
||||
DesignatedContact.create(Type.BILLING, sh8013Key),
|
||||
DesignatedContact.create(Type.TECH, sh8013Key)))
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(loadFile("generic_success_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_removeClientUpdateProhibited() throws Exception {
|
||||
persistReferencedEntities();
|
||||
persistResource(
|
||||
persistApplication()
|
||||
.asBuilder()
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.CLIENT_UPDATE_PROHIBITED))
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
runFlow();
|
||||
assertAboutApplications()
|
||||
.that(reloadDomainApplication())
|
||||
.doesNotHaveStatusValue(StatusValue.CLIENT_UPDATE_PROHIBITED);
|
||||
}
|
||||
|
||||
private void doSecDnsSuccessfulTest(
|
||||
String xmlFilename,
|
||||
ImmutableSet<DelegationSignerData> originalDsData,
|
||||
ImmutableSet<DelegationSignerData> expectedDsData)
|
||||
throws Exception {
|
||||
setEppInput(xmlFilename);
|
||||
persistResource(newApplicationBuilder().setDsData(originalDsData).build());
|
||||
assertTransactionalFlow(true);
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(loadFile("generic_success_response.xml"));
|
||||
assertAboutApplications()
|
||||
.that(reloadDomainApplication())
|
||||
.hasExactlyDsData(expectedDsData)
|
||||
.and()
|
||||
.hasOnlyOneHistoryEntryWhich()
|
||||
.hasType(HistoryEntry.Type.DOMAIN_APPLICATION_UPDATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_secDnsAdd() throws Exception {
|
||||
doSecDnsSuccessfulTest(
|
||||
"domain_update_sunrise_dsdata_add.xml",
|
||||
null,
|
||||
ImmutableSet.of(
|
||||
DelegationSignerData.create(12346, 3, 1, base16().decode("38EC35D5B3A34B44C39B"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_secDnsAddPreservesExisting() throws Exception {
|
||||
doSecDnsSuccessfulTest(
|
||||
"domain_update_sunrise_dsdata_add.xml",
|
||||
ImmutableSet.of(SOME_DSDATA),
|
||||
ImmutableSet.of(
|
||||
SOME_DSDATA,
|
||||
DelegationSignerData.create(12346, 3, 1, base16().decode("38EC35D5B3A34B44C39B"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_secDnsAddToMaxRecords() throws Exception {
|
||||
ImmutableSet.Builder<DelegationSignerData> builder = new ImmutableSet.Builder<>();
|
||||
for (int i = 0; i < 7; ++i) {
|
||||
builder.add(DelegationSignerData.create(i, 2, 3, new byte[] {0, 1, 2}));
|
||||
}
|
||||
ImmutableSet<DelegationSignerData> commonDsData = builder.build();
|
||||
|
||||
doSecDnsSuccessfulTest(
|
||||
"domain_update_sunrise_dsdata_add.xml",
|
||||
commonDsData,
|
||||
ImmutableSet.copyOf(
|
||||
union(
|
||||
commonDsData,
|
||||
ImmutableSet.of(
|
||||
DelegationSignerData.create(
|
||||
12346, 3, 1, base16().decode("38EC35D5B3A34B44C39B"))))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_secDnsRemove() throws Exception {
|
||||
doSecDnsSuccessfulTest(
|
||||
"domain_update_sunrise_dsdata_rem.xml",
|
||||
ImmutableSet.of(
|
||||
SOME_DSDATA,
|
||||
DelegationSignerData.create(12346, 3, 1, base16().decode("38EC35D5B3A34B44C39B"))),
|
||||
ImmutableSet.of(SOME_DSDATA));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_secDnsRemoveAll() throws Exception {
|
||||
// As an aside, this test also validates that it's ok to set the 'urgent' attribute to false.
|
||||
doSecDnsSuccessfulTest(
|
||||
"domain_update_sunrise_dsdata_rem_all.xml",
|
||||
ImmutableSet.of(
|
||||
SOME_DSDATA,
|
||||
DelegationSignerData.create(12346, 3, 1, base16().decode("38EC35D5B3A34B44C39B"))),
|
||||
ImmutableSet.of());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_secDnsAddRemove() throws Exception {
|
||||
doSecDnsSuccessfulTest(
|
||||
"domain_update_sunrise_dsdata_add_rem.xml",
|
||||
ImmutableSet.of(
|
||||
SOME_DSDATA,
|
||||
DelegationSignerData.create(12345, 3, 1, base16().decode("38EC35D5B3A34B33C99B"))),
|
||||
ImmutableSet.of(
|
||||
SOME_DSDATA,
|
||||
DelegationSignerData.create(12346, 3, 1, base16().decode("38EC35D5B3A34B44C39B"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_secDnsAddRemoveToMaxRecords() throws Exception {
|
||||
ImmutableSet.Builder<DelegationSignerData> builder = new ImmutableSet.Builder<>();
|
||||
for (int i = 0; i < 7; ++i) {
|
||||
builder.add(DelegationSignerData.create(i, 2, 3, new byte[] {0, 1, 2}));
|
||||
}
|
||||
ImmutableSet<DelegationSignerData> commonDsData = builder.build();
|
||||
|
||||
doSecDnsSuccessfulTest(
|
||||
"domain_update_sunrise_dsdata_add_rem.xml",
|
||||
ImmutableSet.copyOf(
|
||||
union(
|
||||
commonDsData,
|
||||
ImmutableSet.of(
|
||||
DelegationSignerData.create(
|
||||
12345, 3, 1, base16().decode("38EC35D5B3A34B33C99B"))))),
|
||||
ImmutableSet.copyOf(
|
||||
union(
|
||||
commonDsData,
|
||||
ImmutableSet.of(
|
||||
DelegationSignerData.create(
|
||||
12346, 3, 1, base16().decode("38EC35D5B3A34B44C39B"))))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_secDnsAddRemoveSame() throws Exception {
|
||||
// Adding and removing the same dsData is a no-op because removes are processed first.
|
||||
doSecDnsSuccessfulTest(
|
||||
"domain_update_sunrise_dsdata_add_rem_same.xml",
|
||||
ImmutableSet.of(
|
||||
SOME_DSDATA,
|
||||
DelegationSignerData.create(12345, 3, 1, base16().decode("38EC35D5B3A34B33C99B"))),
|
||||
ImmutableSet.of(
|
||||
SOME_DSDATA,
|
||||
DelegationSignerData.create(12345, 3, 1, base16().decode("38EC35D5B3A34B33C99B"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_secDnsRemoveAlreadyNotThere() throws Exception {
|
||||
// Removing a dsData that isn't there is a no-op.
|
||||
doSecDnsSuccessfulTest(
|
||||
"domain_update_sunrise_dsdata_rem.xml",
|
||||
ImmutableSet.of(SOME_DSDATA),
|
||||
ImmutableSet.of(SOME_DSDATA));
|
||||
}
|
||||
|
||||
private void doSecDnsFailingTest(
|
||||
Class<? extends EppException> expectedException, String xmlFilename) {
|
||||
setEppInput(xmlFilename);
|
||||
persistReferencedEntities();
|
||||
persistNewApplication();
|
||||
EppException thrown = assertThrows(expectedException, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_secDnsAllCannotBeFalse() {
|
||||
doSecDnsFailingTest(
|
||||
SecDnsAllUsageException.class, "domain_update_sunrise_dsdata_rem_all_false.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_secDnsEmptyNotAllowed() {
|
||||
doSecDnsFailingTest(EmptySecDnsUpdateException.class, "domain_update_sunrise_dsdata_empty.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_secDnsUrgentNotSupported() {
|
||||
doSecDnsFailingTest(
|
||||
UrgentAttributeNotSupportedException.class, "domain_update_sunrise_dsdata_urgent.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_secDnsChangeNotSupported() {
|
||||
doSecDnsFailingTest(
|
||||
MaxSigLifeChangeNotSupportedException.class, "domain_update_sunrise_maxsiglife.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_secDnsTooManyDsRecords() {
|
||||
ImmutableSet.Builder<DelegationSignerData> builder = new ImmutableSet.Builder<>();
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
builder.add(DelegationSignerData.create(i, 2, 3, new byte[] {0, 1, 2}));
|
||||
}
|
||||
|
||||
setEppInput("domain_update_sunrise_dsdata_add.xml");
|
||||
persistResource(newApplicationBuilder().setDsData(builder.build()).build());
|
||||
EppException thrown = assertThrows(TooManyDsRecordsException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
private void modifyApplicationToHave13Nameservers() throws Exception {
|
||||
ImmutableSet.Builder<Key<HostResource>> nameservers = new ImmutableSet.Builder<>();
|
||||
for (int i = 1; i < 15; i++) {
|
||||
if (i != 2) { // Skip 2 since that's the one that the tests will add.
|
||||
nameservers.add(
|
||||
Key.create(
|
||||
loadByForeignKey(
|
||||
HostResource.class, String.format("ns%d.example.tld", i), clock.nowUtc())
|
||||
.get()));
|
||||
}
|
||||
}
|
||||
persistResource(
|
||||
reloadDomainApplication().asBuilder().setNameservers(nameservers.build()).build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_tooManyNameservers() throws Exception {
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
// Modify application to have 13 nameservers. We will then remove one and add one in the test.
|
||||
modifyApplicationToHave13Nameservers();
|
||||
setEppInput("domain_update_sunrise_add_nameserver.xml");
|
||||
EppException thrown = assertThrows(TooManyNameserversException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_wrongExtension() {
|
||||
setEppInput("domain_update_sunrise_wrong_extension.xml");
|
||||
EppException thrown = assertThrows(UnimplementedExtensionException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_applicationDomainNameMismatch() {
|
||||
persistReferencedEntities();
|
||||
persistResource(newApplicationBuilder().setFullyQualifiedDomainName("something.tld").build());
|
||||
EppException thrown = assertThrows(ApplicationDomainNameMismatchException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_neverExisted() throws Exception {
|
||||
persistReferencedEntities();
|
||||
ResourceDoesNotExistException thrown =
|
||||
assertThrows(ResourceDoesNotExistException.class, this::runFlow);
|
||||
assertThat(thrown).hasMessageThat().contains(String.format("(%s)", getUniqueIdFromCommand()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_existedButWasDeleted() throws Exception {
|
||||
persistReferencedEntities();
|
||||
persistResource(newApplicationBuilder().setDeletionTime(START_OF_TIME).build());
|
||||
ResourceDoesNotExistException thrown =
|
||||
assertThrows(ResourceDoesNotExistException.class, this::runFlow);
|
||||
assertThat(thrown).hasMessageThat().contains(String.format("(%s)", getUniqueIdFromCommand()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientUpdateProhibited() {
|
||||
setEppInput("domain_update_sunrise_authinfo.xml");
|
||||
persistReferencedEntities();
|
||||
persistResource(
|
||||
newApplicationBuilder()
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.CLIENT_UPDATE_PROHIBITED))
|
||||
.build());
|
||||
EppException thrown =
|
||||
assertThrows(ResourceHasClientUpdateProhibitedException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_serverUpdateProhibited() {
|
||||
persistReferencedEntities();
|
||||
persistResource(
|
||||
newApplicationBuilder()
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.SERVER_UPDATE_PROHIBITED))
|
||||
.build());
|
||||
ResourceStatusProhibitsOperationException thrown =
|
||||
assertThrows(ResourceStatusProhibitsOperationException.class, this::runFlow);
|
||||
assertThat(thrown).hasMessageThat().contains("serverUpdateProhibited");
|
||||
}
|
||||
|
||||
private void doIllegalApplicationStatusTest(ApplicationStatus status) {
|
||||
persistReferencedEntities();
|
||||
persistResource(newApplicationBuilder().setApplicationStatus(status).build());
|
||||
EppException thrown =
|
||||
assertThrows(ApplicationStatusProhibitsUpdateException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_allocatedApplicationStatus() {
|
||||
doIllegalApplicationStatusTest(ApplicationStatus.ALLOCATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_invalidApplicationStatus() {
|
||||
doIllegalApplicationStatusTest(ApplicationStatus.INVALID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_rejectedApplicationStatus() {
|
||||
doIllegalApplicationStatusTest(ApplicationStatus.REJECTED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_missingHost() {
|
||||
persistActiveHost("ns1.example.tld");
|
||||
persistActiveContact("sh8013");
|
||||
persistActiveContact("mak21");
|
||||
persistNewApplication();
|
||||
LinkedResourcesDoNotExistException thrown =
|
||||
assertThrows(LinkedResourcesDoNotExistException.class, this::runFlow);
|
||||
assertThat(thrown).hasMessageThat().contains("(ns2.example.tld)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_missingContact() {
|
||||
persistActiveHost("ns1.example.tld");
|
||||
persistActiveHost("ns2.example.tld");
|
||||
persistActiveContact("mak21");
|
||||
persistNewApplication();
|
||||
LinkedResourcesDoNotExistException thrown =
|
||||
assertThrows(LinkedResourcesDoNotExistException.class, this::runFlow);
|
||||
assertThat(thrown).hasMessageThat().contains("(sh8013)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_addingDuplicateContact() throws Exception {
|
||||
persistReferencedEntities();
|
||||
persistActiveContact("foo");
|
||||
persistNewApplication();
|
||||
// Add a tech contact to the persisted entity, which should cause the flow to fail when it tries
|
||||
// to add "mak21" as a second tech contact.
|
||||
persistResource(
|
||||
reloadDomainApplication()
|
||||
.asBuilder()
|
||||
.setContacts(
|
||||
ImmutableSet.of(
|
||||
DesignatedContact.create(
|
||||
Type.TECH,
|
||||
Key.create(
|
||||
loadByForeignKey(ContactResource.class, "foo", clock.nowUtc()).get()))))
|
||||
.build());
|
||||
EppException thrown = assertThrows(DuplicateContactForRoleException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientProhibitedStatusValue() {
|
||||
setEppInput("domain_update_sunrise_prohibited_status.xml");
|
||||
persistReferencedEntities();
|
||||
persistNewApplication();
|
||||
EppException thrown = assertThrows(StatusNotClientSettableException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_superuserProhibitedStatusValue() throws Exception {
|
||||
setEppInput("domain_update_sunrise_prohibited_status.xml");
|
||||
persistReferencedEntities();
|
||||
persistNewApplication();
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(
|
||||
CommitMode.LIVE, UserPrivileges.SUPERUSER, loadFile("generic_success_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_duplicateContactInCommand() {
|
||||
setEppInput("domain_update_sunrise_duplicate_contact.xml");
|
||||
persistReferencedEntities();
|
||||
persistNewApplication();
|
||||
EppException thrown = assertThrows(DuplicateContactForRoleException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_missingContactType() {
|
||||
setEppInput("domain_update_sunrise_missing_contact_type.xml");
|
||||
persistReferencedEntities();
|
||||
persistNewApplication();
|
||||
// We need to test for missing type, but not for invalid - the schema enforces that for us.
|
||||
EppException thrown = assertThrows(MissingContactTypeException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unauthorizedClient() {
|
||||
sessionMetadata.setClientId("NewRegistrar");
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
EppException thrown = assertThrows(ResourceNotOwnedException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_superuserUnauthorizedClient() throws Exception {
|
||||
sessionMetadata.setClientId("NewRegistrar");
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(
|
||||
CommitMode.LIVE, UserPrivileges.SUPERUSER, loadFile("generic_success_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_notAuthorizedForTld() {
|
||||
persistResource(
|
||||
loadRegistrar("TheRegistrar").asBuilder().setAllowedTlds(ImmutableSet.of()).build());
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
EppException thrown = assertThrows(NotAuthorizedForTldException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_superuserNotAuthorizedForTld() throws Exception {
|
||||
persistResource(
|
||||
loadRegistrar("TheRegistrar").asBuilder().setAllowedTlds(ImmutableSet.of()).build());
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(
|
||||
CommitMode.LIVE, UserPrivileges.SUPERUSER, loadFile("generic_success_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_sameNameserverAddedAndRemoved() {
|
||||
setEppInput("domain_update_sunrise_add_remove_same_host.xml");
|
||||
persistReferencedEntities();
|
||||
persistResource(
|
||||
newApplicationBuilder()
|
||||
.setNameservers(
|
||||
ImmutableSet.of(
|
||||
Key.create(
|
||||
loadByForeignKey(HostResource.class, "ns1.example.tld", clock.nowUtc())
|
||||
.get())))
|
||||
.build());
|
||||
EppException thrown = assertThrows(AddRemoveSameValueException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_sameContactAddedAndRemoved() {
|
||||
setEppInput("domain_update_sunrise_add_remove_same_contact.xml");
|
||||
persistReferencedEntities();
|
||||
persistResource(
|
||||
newApplicationBuilder()
|
||||
.setContacts(
|
||||
ImmutableSet.of(
|
||||
DesignatedContact.create(
|
||||
Type.TECH,
|
||||
Key.create(
|
||||
loadByForeignKey(ContactResource.class, "sh8013", clock.nowUtc())
|
||||
.get()))))
|
||||
.build());
|
||||
EppException thrown = assertThrows(AddRemoveSameValueException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_removeAdmin() {
|
||||
setEppInput("domain_update_sunrise_remove_admin.xml");
|
||||
persistReferencedEntities();
|
||||
persistResource(
|
||||
newApplicationBuilder()
|
||||
.setContacts(
|
||||
ImmutableSet.of(
|
||||
DesignatedContact.create(Type.ADMIN, Key.create(sh8013Contact)),
|
||||
DesignatedContact.create(Type.TECH, Key.create(sh8013Contact))))
|
||||
.build());
|
||||
EppException thrown = assertThrows(MissingAdminContactException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_removeTech() {
|
||||
setEppInput("domain_update_sunrise_remove_tech.xml");
|
||||
persistReferencedEntities();
|
||||
persistResource(
|
||||
newApplicationBuilder()
|
||||
.setContacts(
|
||||
ImmutableSet.of(
|
||||
DesignatedContact.create(Type.ADMIN, Key.create(sh8013Contact)),
|
||||
DesignatedContact.create(Type.TECH, Key.create(sh8013Contact))))
|
||||
.build());
|
||||
EppException thrown = assertThrows(MissingTechnicalContactException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_newRegistrantNotWhitelisted() {
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setAllowedRegistrantContactIds(ImmutableSet.of("contact1234"))
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
EppException thrown = assertThrows(RegistrantNotAllowedException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_newNameserverNotWhitelisted() {
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setAllowedFullyQualifiedHostNames(ImmutableSet.of("ns1.example.foo"))
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
EppException thrown = assertThrows(NameserversNotAllowedForTldException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_nameserverAndRegistrantWhitelisted() throws Exception {
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setAllowedRegistrantContactIds(ImmutableSet.of("sh8013"))
|
||||
.setAllowedFullyQualifiedHostNames(ImmutableSet.of("ns2.example.tld"))
|
||||
.build());
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_tldWithNameserverWhitelist_removeLastNameserver() {
|
||||
setEppInput("domain_update_sunrise_remove_nameserver.xml");
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setAllowedFullyQualifiedHostNames(
|
||||
ImmutableSet.of("ns1.example.tld", "ns2.example.tld"))
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
NameserversNotSpecifiedForTldWithNameserverWhitelistException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_tldWithNameserverWhitelist_removeNameserver() throws Exception {
|
||||
setEppInput("domain_update_sunrise_remove_nameserver.xml");
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
persistResource(
|
||||
reloadDomainApplication()
|
||||
.asBuilder()
|
||||
.addNameserver(
|
||||
Key.create(
|
||||
loadByForeignKey(HostResource.class, "ns2.example.tld", clock.nowUtc()).get()))
|
||||
.build());
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setAllowedFullyQualifiedHostNames(
|
||||
ImmutableSet.of("ns1.example.tld", "ns2.example.tld"))
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_domainNameserverRestricted_addedNameserverAllowed() throws Exception {
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setReservedLists(
|
||||
persistReservedList(
|
||||
"reserved", "example,NAMESERVER_RESTRICTED,ns1.example.tld:ns2.example.tld"))
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_domainNameserverRestricted_addedNameserverDisallowed() {
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setReservedLists(
|
||||
persistReservedList(
|
||||
"reserved", "example,NAMESERVER_RESTRICTED,ns1.example.tld:ns3.example.tld"))
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
NameserversNotAllowedForDomainException thrown =
|
||||
assertThrows(NameserversNotAllowedForDomainException.class, this::runFlow);
|
||||
assertThat(thrown).hasMessageThat().contains("ns2.example.tld");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_domainNameserverRestricted_removeLastNameserver() {
|
||||
setEppInput("domain_update_sunrise_remove_nameserver.xml");
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setReservedLists(
|
||||
persistReservedList(
|
||||
"reserved", "example,NAMESERVER_RESTRICTED,ns1.example.tld:ns2.example.tld"))
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
NameserversNotSpecifiedForNameserverRestrictedDomainException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_domainNameserverRestricted_removeNameservers() throws Exception {
|
||||
setEppInput("domain_update_sunrise_remove_nameserver.xml");
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
persistResource(
|
||||
reloadDomainApplication()
|
||||
.asBuilder()
|
||||
.addNameserver(
|
||||
Key.create(
|
||||
loadByForeignKey(HostResource.class, "ns2.example.tld", clock.nowUtc()).get()))
|
||||
.build());
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setReservedLists(
|
||||
persistReservedList(
|
||||
"reserved", "example,NAMESERVER_RESTRICTED,ns1.example.tld:ns2.example.tld"))
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_addedNameserversAllowedInTldAndDomainNameserversWhitelists()
|
||||
throws Exception {
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setAllowedFullyQualifiedHostNames(
|
||||
ImmutableSet.of("ns1.example.tld", "ns2.example.tld"))
|
||||
.setReservedLists(
|
||||
persistReservedList(
|
||||
"reserved", "example,NAMESERVER_RESTRICTED,ns1.example.tld:ns2.example.tld"))
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_addedNameserversAllowedInTld_disallowedInDomainNameserversWhitelists() {
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setAllowedFullyQualifiedHostNames(
|
||||
ImmutableSet.of("ns1.example.tld", "ns2.example.tld"))
|
||||
.setReservedLists(
|
||||
persistReservedList(
|
||||
"reserved", "example,NAMESERVER_RESTRICTED,ns1.example.tld:ns3.example.tld"))
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
NameserversNotAllowedForDomainException thrown =
|
||||
assertThrows(NameserversNotAllowedForDomainException.class, this::runFlow);
|
||||
assertThat(thrown).hasMessageThat().contains("ns2.example.tld");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_addedNameserversDisallowedInTld_AllowedInDomainNameserversWhitelists() {
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setAllowedFullyQualifiedHostNames(
|
||||
ImmutableSet.of("ns1.example.tld", "ns3.example.tld"))
|
||||
.setReservedLists(
|
||||
persistReservedList(
|
||||
"reserved", "example,NAMESERVER_RESTRICTED,ns1.example.tld:ns2.example.tld"))
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
NameserversNotAllowedForTldException thrown =
|
||||
assertThrows(NameserversNotAllowedForTldException.class, this::runFlow);
|
||||
assertThat(thrown).hasMessageThat().contains("ns2.example.tld");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_customPricingLogic_feeMismatch() {
|
||||
persistReferencedEntities();
|
||||
persistResource(
|
||||
newDomainApplication("non-free-update.tld").asBuilder().setRepoId("1-ROID").build());
|
||||
setEppInput(
|
||||
"domain_update_sunrise_fee.xml",
|
||||
ImmutableMap.of("DOMAIN", "non-free-update.tld", "AMOUNT", "12.00"));
|
||||
clock.advanceOneMilli();
|
||||
EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
persistReferencedEntities();
|
||||
persistApplication();
|
||||
clock.advanceOneMilli();
|
||||
runFlow();
|
||||
assertIcannReportingActivityFieldLogged("srs-dom-update");
|
||||
assertTldsFieldLogged("tld");
|
||||
}
|
||||
}
|
|
@ -15,10 +15,10 @@
|
|||
package google.registry.flows.domain;
|
||||
|
||||
import static google.registry.model.eppoutput.CheckData.DomainCheck.create;
|
||||
import static google.registry.model.registry.Registry.TldState.START_DATE_SUNRISE;
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
import static google.registry.testing.DatastoreHelper.createTlds;
|
||||
import static google.registry.testing.DatastoreHelper.loadRegistrar;
|
||||
import static google.registry.testing.DatastoreHelper.newDomainApplication;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveDomain;
|
||||
import static google.registry.testing.DatastoreHelper.persistDeletedDomain;
|
||||
import static google.registry.testing.DatastoreHelper.persistPremiumList;
|
||||
|
@ -59,8 +59,6 @@ import google.registry.flows.domain.DomainFlowUtils.TransfersAreAlwaysForOneYear
|
|||
import google.registry.flows.domain.DomainFlowUtils.UnknownFeeCommandException;
|
||||
import google.registry.flows.exceptions.TooManyResourceChecksException;
|
||||
import google.registry.model.domain.DomainResource;
|
||||
import google.registry.model.domain.launch.ApplicationStatus;
|
||||
import google.registry.model.domain.launch.LaunchPhase;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.model.registry.Registry.TldState;
|
||||
|
@ -261,84 +259,6 @@ public class DomainCheckFlowTest
|
|||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_pendingSunriseApplicationInGeneralAvailability() throws Exception {
|
||||
createTld("tld", TldState.GENERAL_AVAILABILITY);
|
||||
persistResource(newDomainApplication("example2.tld").asBuilder().build());
|
||||
doCheckTest(
|
||||
create(true, "example1.tld", null),
|
||||
create(false, "example2.tld", "Pending allocation"),
|
||||
create(true, "example3.tld", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_pendingLandrushApplicationInGeneralAvailability() throws Exception {
|
||||
createTld("tld", TldState.GENERAL_AVAILABILITY);
|
||||
persistResource(
|
||||
newDomainApplication("example2.tld").asBuilder().setPhase(LaunchPhase.LANDRUSH).build());
|
||||
doCheckTest(
|
||||
create(true, "example1.tld", null),
|
||||
create(false, "example2.tld", "Pending allocation"),
|
||||
create(true, "example3.tld", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_pendingSunriseApplicationInQuietPeriod() throws Exception {
|
||||
createTld("tld", TldState.QUIET_PERIOD);
|
||||
persistResource(newDomainApplication("example2.tld").asBuilder().build());
|
||||
doCheckTest(
|
||||
create(true, "example1.tld", null),
|
||||
create(false, "example2.tld", "Pending allocation"),
|
||||
create(true, "example3.tld", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_pendingLandrushApplicationInQuietPeriod() throws Exception {
|
||||
createTld("tld", TldState.QUIET_PERIOD);
|
||||
persistResource(
|
||||
newDomainApplication("example2.tld").asBuilder().setPhase(LaunchPhase.LANDRUSH).build());
|
||||
doCheckTest(
|
||||
create(true, "example1.tld", null),
|
||||
create(false, "example2.tld", "Pending allocation"),
|
||||
create(true, "example3.tld", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_pendingSunriseApplicationInSunrise() throws Exception {
|
||||
createTld("tld", TldState.SUNRISE);
|
||||
persistResource(newDomainApplication("example2.tld").asBuilder().build());
|
||||
doCheckTest(
|
||||
create(true, "example1.tld", null),
|
||||
create(true, "example2.tld", null),
|
||||
create(true, "example3.tld", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_pendingLandrushApplicationInLandrush() throws Exception {
|
||||
createTld("tld", TldState.LANDRUSH);
|
||||
persistResource(
|
||||
newDomainApplication("example2.tld").asBuilder().setPhase(LaunchPhase.LANDRUSH).build());
|
||||
doCheckTest(
|
||||
create(true, "example1.tld", null),
|
||||
create(true, "example2.tld", null),
|
||||
create(true, "example3.tld", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_rejectedApplication() throws Exception {
|
||||
createTld("tld", TldState.LANDRUSH);
|
||||
persistResource(
|
||||
newDomainApplication("example2.tld")
|
||||
.asBuilder()
|
||||
.setPhase(LaunchPhase.LANDRUSH)
|
||||
.setApplicationStatus(ApplicationStatus.REJECTED)
|
||||
.build());
|
||||
doCheckTest(
|
||||
create(true, "example1.tld", null),
|
||||
create(true, "example2.tld", null),
|
||||
create(true, "example3.tld", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_tooManyIds() {
|
||||
setEppInput("domain_check_51.xml");
|
||||
|
@ -693,7 +613,7 @@ public class DomainCheckFlowTest
|
|||
|
||||
@Test
|
||||
public void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v06() throws Exception {
|
||||
createTld("tld", TldState.SUNRISE);
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
|
@ -707,7 +627,7 @@ public class DomainCheckFlowTest
|
|||
@Test
|
||||
public void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v11_create()
|
||||
throws Exception {
|
||||
createTld("tld", TldState.SUNRISE);
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
|
@ -720,7 +640,7 @@ public class DomainCheckFlowTest
|
|||
|
||||
@Test
|
||||
public void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v11_renew() throws Exception {
|
||||
createTld("tld", TldState.SUNRISE);
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
|
@ -734,7 +654,7 @@ public class DomainCheckFlowTest
|
|||
@Test
|
||||
public void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v11_transfer()
|
||||
throws Exception {
|
||||
createTld("tld", TldState.SUNRISE);
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
|
@ -748,7 +668,7 @@ public class DomainCheckFlowTest
|
|||
@Test
|
||||
public void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v11_restore()
|
||||
throws Exception {
|
||||
createTld("tld", TldState.SUNRISE);
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
|
@ -761,7 +681,7 @@ public class DomainCheckFlowTest
|
|||
|
||||
@Test
|
||||
public void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v12() throws Exception {
|
||||
createTld("tld", TldState.SUNRISE);
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue