mirror of
https://github.com/google/nomulus
synced 2026-05-22 15:51:49 +00:00
Compare commits
4 Commits
nomulus-20
...
nomulus-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45d90e7c68 | ||
|
|
028005906a | ||
|
|
78d78e21cb | ||
|
|
2f3ac2e43b |
@@ -220,7 +220,8 @@ public class TlsCredentials implements TransportCredentials {
|
||||
super(
|
||||
clientInetAddr.isPresent()
|
||||
? String.format(
|
||||
"Registrar IP address %s is not in stored allow list", clientInetAddr.get())
|
||||
"Registrar IP address %s is not in stored allow list",
|
||||
clientInetAddr.get().getHostAddress())
|
||||
: "Registrar IP address is not in stored allow list");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ 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.token.AllocationTokenFlowUtils;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingEvent.Flag;
|
||||
@@ -55,7 +56,10 @@ import google.registry.model.domain.DomainHistory.DomainHistoryId;
|
||||
import google.registry.model.domain.GracePeriod;
|
||||
import google.registry.model.domain.metadata.MetadataExtension;
|
||||
import google.registry.model.domain.rgp.GracePeriodStatus;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.domain.token.AllocationTokenExtension;
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.eppoutput.EppResponse;
|
||||
import google.registry.model.poll.PollMessage;
|
||||
import google.registry.model.reporting.DomainTransactionRecord;
|
||||
@@ -85,6 +89,18 @@ import org.joda.time.DateTime;
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}
|
||||
* @error {@link google.registry.flows.exceptions.NotPendingTransferException}
|
||||
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
|
||||
* @error {@link
|
||||
* google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForDomainException}
|
||||
* @error {@link
|
||||
* google.registry.flows.domain.token.AllocationTokenFlowUtils.InvalidAllocationTokenException}
|
||||
* @error {@link
|
||||
* google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotInPromotionException}
|
||||
* @error {@link
|
||||
* google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForRegistrarException}
|
||||
* @error {@link
|
||||
* google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForTldException}
|
||||
* @error {@link
|
||||
* google.registry.flows.domain.token.AllocationTokenFlowUtils.AlreadyRedeemedAllocationTokenException}
|
||||
*/
|
||||
@ReportingSpec(ActivityReportField.DOMAIN_TRANSFER_APPROVE)
|
||||
public final class DomainTransferApproveFlow implements TransactionalFlow {
|
||||
@@ -97,6 +113,8 @@ public final class DomainTransferApproveFlow implements TransactionalFlow {
|
||||
@Inject DomainHistory.Builder historyBuilder;
|
||||
@Inject EppResponse.Builder responseBuilder;
|
||||
@Inject DomainPricingLogic pricingLogic;
|
||||
@Inject AllocationTokenFlowUtils allocationTokenFlowUtils;
|
||||
@Inject EppInput eppInput;
|
||||
|
||||
@Inject DomainTransferApproveFlow() {}
|
||||
|
||||
@@ -106,11 +124,20 @@ public final class DomainTransferApproveFlow implements TransactionalFlow {
|
||||
*/
|
||||
@Override
|
||||
public EppResponse run() throws EppException {
|
||||
extensionManager.register(MetadataExtension.class);
|
||||
extensionManager.register(MetadataExtension.class, AllocationTokenExtension.class);
|
||||
validateRegistrarIsLoggedIn(registrarId);
|
||||
extensionManager.validate();
|
||||
DateTime now = tm().getTransactionTime();
|
||||
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
|
||||
// Currently we do not do anything with this allocation token, but just want it loaded and
|
||||
// available in this flow in case we use it in the future
|
||||
Optional<AllocationToken> allocationToken =
|
||||
allocationTokenFlowUtils.verifyAllocationTokenIfPresent(
|
||||
existingDomain,
|
||||
Registry.get(existingDomain.getTld()),
|
||||
registrarId,
|
||||
now,
|
||||
eppInput.getSingleExtension(AllocationTokenExtension.class));
|
||||
verifyOptionalAuthInfo(authInfo, existingDomain);
|
||||
verifyHasPendingTransfer(existingDomain);
|
||||
verifyResourceOwnership(registrarId, existingDomain);
|
||||
|
||||
@@ -47,6 +47,7 @@ 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.token.AllocationTokenFlowUtils;
|
||||
import google.registry.flows.exceptions.AlreadyPendingTransferException;
|
||||
import google.registry.flows.exceptions.InvalidTransferPeriodValueException;
|
||||
import google.registry.flows.exceptions.ObjectAlreadySponsoredException;
|
||||
@@ -61,6 +62,8 @@ import google.registry.model.domain.fee.FeeTransferCommandExtension;
|
||||
import google.registry.model.domain.fee.FeeTransformResponseExtension;
|
||||
import google.registry.model.domain.metadata.MetadataExtension;
|
||||
import google.registry.model.domain.superuser.DomainTransferRequestSuperuserExtension;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.domain.token.AllocationTokenExtension;
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.eppcommon.Trid;
|
||||
@@ -117,6 +120,18 @@ import org.joda.time.DateTime;
|
||||
* @error {@link DomainFlowUtils.PremiumNameBlockedException}
|
||||
* @error {@link DomainFlowUtils.RegistrarMustBeActiveForThisOperationException}
|
||||
* @error {@link DomainFlowUtils.UnsupportedFeeAttributeException}
|
||||
* @error {@link
|
||||
* google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForDomainException}
|
||||
* @error {@link
|
||||
* google.registry.flows.domain.token.AllocationTokenFlowUtils.InvalidAllocationTokenException}
|
||||
* @error {@link
|
||||
* google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotInPromotionException}
|
||||
* @error {@link
|
||||
* google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForRegistrarException}
|
||||
* @error {@link
|
||||
* google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForTldException}
|
||||
* @error {@link
|
||||
* google.registry.flows.domain.token.AllocationTokenFlowUtils.AlreadyRedeemedAllocationTokenException}
|
||||
*/
|
||||
@ReportingSpec(ActivityReportField.DOMAIN_TRANSFER_REQUEST)
|
||||
public final class DomainTransferRequestFlow implements TransactionalFlow {
|
||||
@@ -138,6 +153,8 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
|
||||
@Inject AsyncTaskEnqueuer asyncTaskEnqueuer;
|
||||
@Inject EppResponse.Builder responseBuilder;
|
||||
@Inject DomainPricingLogic pricingLogic;
|
||||
@Inject AllocationTokenFlowUtils allocationTokenFlowUtils;
|
||||
|
||||
@Inject DomainTransferRequestFlow() {}
|
||||
|
||||
@Override
|
||||
@@ -145,12 +162,22 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
|
||||
extensionManager.register(
|
||||
DomainTransferRequestSuperuserExtension.class,
|
||||
FeeTransferCommandExtension.class,
|
||||
MetadataExtension.class);
|
||||
MetadataExtension.class,
|
||||
AllocationTokenExtension.class);
|
||||
validateRegistrarIsLoggedIn(gainingClientId);
|
||||
verifyRegistrarIsActive(gainingClientId);
|
||||
extensionManager.validate();
|
||||
DateTime now = tm().getTransactionTime();
|
||||
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
|
||||
// Currently we do not do anything with this allocation token, but just want it loaded and
|
||||
// available in this flow in case we use it in the future
|
||||
Optional<AllocationToken> allocationToken =
|
||||
allocationTokenFlowUtils.verifyAllocationTokenIfPresent(
|
||||
existingDomain,
|
||||
Registry.get(existingDomain.getTld()),
|
||||
gainingClientId,
|
||||
now,
|
||||
eppInput.getSingleExtension(AllocationTokenExtension.class));
|
||||
Optional<DomainTransferRequestSuperuserExtension> superuserExtension =
|
||||
eppInput.getSingleExtension(DomainTransferRequestSuperuserExtension.class);
|
||||
Period period =
|
||||
|
||||
@@ -210,7 +210,8 @@ public class Domain extends DomainBase implements ForeignKeyedEppResource {
|
||||
.setSubordinateHosts(domainBase.getSubordinateHosts())
|
||||
.setStatusValues(domainBase.getStatusValues())
|
||||
.setTransferData(domainBase.getTransferData())
|
||||
.setDnsRefreshRequestTime(domainBase.getDnsRefreshRequestTime());
|
||||
.setDnsRefreshRequestTime(domainBase.getDnsRefreshRequestTime())
|
||||
.setCurrentPackageToken(domainBase.getCurrentPackageToken().orElse(null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.domain.launch.LaunchNotice;
|
||||
import google.registry.model.domain.rgp.GracePeriodStatus;
|
||||
import google.registry.model.domain.secdns.DelegationSignerData;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.host.Host;
|
||||
import google.registry.model.poll.PollMessage;
|
||||
@@ -282,6 +283,9 @@ public class DomainBase extends EppResource
|
||||
// TODO(mcilwain): Start using this field once we are further along in the DB migration.
|
||||
@Ignore DateTime dnsRefreshRequestTime;
|
||||
|
||||
/** The {@link AllocationToken} for the package this domain is currently a part of. */
|
||||
@Nullable VKey<AllocationToken> currentPackageToken;
|
||||
|
||||
/**
|
||||
* Returns the DNS refresh request time iff this domain's DNS needs refreshing, otherwise absent.
|
||||
*/
|
||||
@@ -330,6 +334,10 @@ public class DomainBase extends EppResource
|
||||
return smdId;
|
||||
}
|
||||
|
||||
public Optional<VKey<AllocationToken>> getCurrentPackageToken() {
|
||||
return Optional.ofNullable(currentPackageToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the autorenew end time if there is one, otherwise empty.
|
||||
*
|
||||
@@ -938,5 +946,10 @@ public class DomainBase extends EppResource
|
||||
getInstance().lastTransferTime = lastTransferTime;
|
||||
return thisCastToDerived();
|
||||
}
|
||||
|
||||
public B setCurrentPackageToken(@Nullable VKey<AllocationToken> currentPackageToken) {
|
||||
getInstance().currentPackageToken = currentPackageToken;
|
||||
return thisCastToDerived();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
package google.registry.flows;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth8.assertThat;
|
||||
import static google.registry.testing.CertificateSamples.SAMPLE_CERT;
|
||||
import static google.registry.testing.DatabaseHelper.loadRegistrar;
|
||||
@@ -81,16 +82,23 @@ final class TlsCredentialsTest {
|
||||
@Test
|
||||
void test_missingIpAddress_doesntAllowAccess() {
|
||||
TlsCredentials tls =
|
||||
new TlsCredentials(false, Optional.of("certHash"), Optional.empty(), certificateChecker);
|
||||
new TlsCredentials(
|
||||
false, Optional.of("certHash"), Optional.of("127.0.0.1"), certificateChecker);
|
||||
persistResource(
|
||||
loadRegistrar("TheRegistrar")
|
||||
.asBuilder()
|
||||
.setClientCertificate(SAMPLE_CERT, clock.nowUtc())
|
||||
.setIpAddressAllowList(ImmutableSet.of(CidrAddressBlock.create("3.5.8.13")))
|
||||
.build());
|
||||
assertThrows(
|
||||
BadRegistrarIpAddressException.class,
|
||||
() -> tls.validate(Registrar.loadByRegistrarId("TheRegistrar").get(), "password"));
|
||||
|
||||
BadRegistrarIpAddressException thrown =
|
||||
assertThrows(
|
||||
BadRegistrarIpAddressException.class,
|
||||
() -> tls.validate(Registrar.loadByRegistrarId("TheRegistrar").get(), "password"));
|
||||
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.isEqualTo("Registrar IP address 127.0.0.1 is not in stored allow list");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -16,6 +16,8 @@ package google.registry.flows.domain;
|
||||
|
||||
import static com.google.common.collect.MoreCollectors.onlyElement;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_USE;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.UNLIMITED_USE;
|
||||
import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.NET_ADDS_4_YR;
|
||||
import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_SUCCESSFUL;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_CREATE;
|
||||
@@ -43,12 +45,19 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.FlowUtils.NotLoggedInException;
|
||||
import google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException;
|
||||
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
|
||||
import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotInPromotionException;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForDomainException;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForRegistrarException;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForTldException;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AlreadyRedeemedAllocationTokenException;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.InvalidAllocationTokenException;
|
||||
import google.registry.flows.exceptions.NotPendingTransferException;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingEvent.OneTime;
|
||||
@@ -63,6 +72,8 @@ import google.registry.model.domain.GracePeriod;
|
||||
import google.registry.model.domain.Period;
|
||||
import google.registry.model.domain.Period.Unit;
|
||||
import google.registry.model.domain.rgp.GracePeriodStatus;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.domain.token.AllocationToken.TokenStatus;
|
||||
import google.registry.model.eppcommon.AuthInfo.PasswordAuth;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.eppcommon.Trid;
|
||||
@@ -77,6 +88,7 @@ import google.registry.model.transfer.DomainTransferData;
|
||||
import google.registry.model.transfer.TransferResponse.DomainTransferResponse;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Stream;
|
||||
@@ -775,4 +787,115 @@ class DomainTransferApproveFlowTest
|
||||
domain.getRegistrationExpirationTime());
|
||||
assertHistoryEntriesDoNotContainTransferBillingEventsOrGracePeriods();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_allocationToken() throws Exception {
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDomainName("example.tld")
|
||||
.build());
|
||||
doSuccessfulTest(
|
||||
"tld",
|
||||
"domain_transfer_approve_allocation_token.xml",
|
||||
"domain_transfer_approve_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_invalidAllocationToken() throws Exception {
|
||||
setEppInput("domain_transfer_approve_allocation_token.xml");
|
||||
EppException thrown = assertThrows(InvalidAllocationTokenException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_allocationTokenIsForDifferentName() throws Exception {
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDomainName("otherdomain.tld")
|
||||
.build());
|
||||
setEppInput("domain_transfer_approve_allocation_token.xml");
|
||||
EppException thrown =
|
||||
assertThrows(AllocationTokenNotValidForDomainException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_allocationTokenNotActive() throws Exception {
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(UNLIMITED_USE)
|
||||
.setDiscountFraction(0.5)
|
||||
.setTokenStatusTransitions(
|
||||
ImmutableSortedMap.<DateTime, TokenStatus>naturalOrder()
|
||||
.put(START_OF_TIME, TokenStatus.NOT_STARTED)
|
||||
.put(clock.nowUtc().plusDays(1), TokenStatus.VALID)
|
||||
.put(clock.nowUtc().plusDays(60), TokenStatus.ENDED)
|
||||
.build())
|
||||
.build());
|
||||
setEppInput("domain_transfer_approve_allocation_token.xml");
|
||||
EppException thrown = assertThrows(AllocationTokenNotInPromotionException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_allocationTokenNotValidForRegistrar() throws Exception {
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(UNLIMITED_USE)
|
||||
.setAllowedRegistrarIds(ImmutableSet.of("someClientId"))
|
||||
.setDiscountFraction(0.5)
|
||||
.setTokenStatusTransitions(
|
||||
ImmutableSortedMap.<DateTime, TokenStatus>naturalOrder()
|
||||
.put(START_OF_TIME, TokenStatus.NOT_STARTED)
|
||||
.put(clock.nowUtc().minusDays(1), TokenStatus.VALID)
|
||||
.put(clock.nowUtc().plusDays(1), TokenStatus.ENDED)
|
||||
.build())
|
||||
.build());
|
||||
setEppInput("domain_transfer_approve_allocation_token.xml");
|
||||
EppException thrown =
|
||||
assertThrows(AllocationTokenNotValidForRegistrarException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_allocationTokenNotValidForTld() throws Exception {
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(UNLIMITED_USE)
|
||||
.setAllowedTlds(ImmutableSet.of("example"))
|
||||
.setDiscountFraction(0.5)
|
||||
.setTokenStatusTransitions(
|
||||
ImmutableSortedMap.<DateTime, TokenStatus>naturalOrder()
|
||||
.put(START_OF_TIME, TokenStatus.NOT_STARTED)
|
||||
.put(clock.nowUtc().minusDays(1), TokenStatus.VALID)
|
||||
.put(clock.nowUtc().plusDays(1), TokenStatus.ENDED)
|
||||
.build())
|
||||
.build());
|
||||
setEppInput("domain_transfer_approve_allocation_token.xml");
|
||||
EppException thrown = assertThrows(AllocationTokenNotValidForTldException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_allocationTokenAlreadyRedeemed() throws Exception {
|
||||
Domain domain = DatabaseHelper.newDomain("foo.tld");
|
||||
Key<HistoryEntry> historyEntryKey = Key.create(Key.create(domain), HistoryEntry.class, 505L);
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setRedemptionHistoryEntry(HistoryEntry.createVKey(historyEntryKey))
|
||||
.build());
|
||||
setEppInput("domain_transfer_approve_allocation_token.xml");
|
||||
EppException thrown =
|
||||
assertThrows(AlreadyRedeemedAllocationTokenException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ import static com.google.common.truth.Truth8.assertThat;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.PARAM_REQUESTED_TIME;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.PARAM_RESOURCE_KEY;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_ACTIONS;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_USE;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.UNLIMITED_USE;
|
||||
import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_SUCCESSFUL;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_CREATE;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST;
|
||||
@@ -59,6 +61,7 @@ import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.batch.ResaveEntityAction;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppRequestSource;
|
||||
@@ -76,6 +79,12 @@ import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException
|
||||
import google.registry.flows.domain.DomainFlowUtils.PremiumNameBlockedException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.RegistrarMustBeActiveForThisOperationException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.UnsupportedFeeAttributeException;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotInPromotionException;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForDomainException;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForRegistrarException;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForTldException;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AlreadyRedeemedAllocationTokenException;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.InvalidAllocationTokenException;
|
||||
import google.registry.flows.exceptions.AlreadyPendingTransferException;
|
||||
import google.registry.flows.exceptions.InvalidTransferPeriodValueException;
|
||||
import google.registry.flows.exceptions.MissingTransferRequestAuthInfoException;
|
||||
@@ -94,6 +103,8 @@ import google.registry.model.domain.GracePeriod;
|
||||
import google.registry.model.domain.Period;
|
||||
import google.registry.model.domain.Period.Unit;
|
||||
import google.registry.model.domain.rgp.GracePeriodStatus;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.domain.token.AllocationToken.TokenStatus;
|
||||
import google.registry.model.eppcommon.AuthInfo.PasswordAuth;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.eppcommon.Trid;
|
||||
@@ -111,6 +122,7 @@ import google.registry.model.transfer.TransferResponse;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.testing.CloudTasksHelper.TaskMatcher;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@@ -1677,4 +1689,120 @@ class DomainTransferRequestFlowTest
|
||||
DomainTransactionRecord.create(
|
||||
"tld", clock.nowUtc().plusDays(5), TRANSFER_SUCCESSFUL, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_allocationToken() throws Exception {
|
||||
setupDomain("example", "tld");
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDomainName("example.tld")
|
||||
.build());
|
||||
doSuccessfulTest(
|
||||
"domain_transfer_request_allocation_token.xml", "domain_transfer_request_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_invalidAllocationToken() throws Exception {
|
||||
setupDomain("example", "tld");
|
||||
setEppInput("domain_transfer_request_allocation_token.xml");
|
||||
EppException thrown = assertThrows(InvalidAllocationTokenException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_allocationTokenIsForDifferentName() throws Exception {
|
||||
setupDomain("example", "tld");
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDomainName("otherdomain.tld")
|
||||
.build());
|
||||
setEppInput("domain_transfer_request_allocation_token.xml");
|
||||
EppException thrown =
|
||||
assertThrows(AllocationTokenNotValidForDomainException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_allocationTokenNotActive() throws Exception {
|
||||
setupDomain("example", "tld");
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(UNLIMITED_USE)
|
||||
.setDiscountFraction(0.5)
|
||||
.setTokenStatusTransitions(
|
||||
ImmutableSortedMap.<DateTime, TokenStatus>naturalOrder()
|
||||
.put(START_OF_TIME, TokenStatus.NOT_STARTED)
|
||||
.put(clock.nowUtc().plusDays(1), TokenStatus.VALID)
|
||||
.put(clock.nowUtc().plusDays(60), TokenStatus.ENDED)
|
||||
.build())
|
||||
.build());
|
||||
setEppInput("domain_transfer_request_allocation_token.xml");
|
||||
EppException thrown = assertThrows(AllocationTokenNotInPromotionException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_allocationTokenNotValidForRegistrar() throws Exception {
|
||||
setupDomain("example", "tld");
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(UNLIMITED_USE)
|
||||
.setAllowedRegistrarIds(ImmutableSet.of("someClientId"))
|
||||
.setDiscountFraction(0.5)
|
||||
.setTokenStatusTransitions(
|
||||
ImmutableSortedMap.<DateTime, TokenStatus>naturalOrder()
|
||||
.put(START_OF_TIME, TokenStatus.NOT_STARTED)
|
||||
.put(clock.nowUtc().minusDays(1), TokenStatus.VALID)
|
||||
.put(clock.nowUtc().plusDays(1), TokenStatus.ENDED)
|
||||
.build())
|
||||
.build());
|
||||
setEppInput("domain_transfer_request_allocation_token.xml");
|
||||
EppException thrown =
|
||||
assertThrows(AllocationTokenNotValidForRegistrarException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_allocationTokenNotValidForTld() throws Exception {
|
||||
setupDomain("example", "tld");
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(UNLIMITED_USE)
|
||||
.setAllowedTlds(ImmutableSet.of("example"))
|
||||
.setDiscountFraction(0.5)
|
||||
.setTokenStatusTransitions(
|
||||
ImmutableSortedMap.<DateTime, TokenStatus>naturalOrder()
|
||||
.put(START_OF_TIME, TokenStatus.NOT_STARTED)
|
||||
.put(clock.nowUtc().minusDays(1), TokenStatus.VALID)
|
||||
.put(clock.nowUtc().plusDays(1), TokenStatus.ENDED)
|
||||
.build())
|
||||
.build());
|
||||
setEppInput("domain_transfer_request_allocation_token.xml");
|
||||
EppException thrown = assertThrows(AllocationTokenNotValidForTldException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_allocationTokenAlreadyRedeemed() throws Exception {
|
||||
setupDomain("example", "tld");
|
||||
Domain domain = DatabaseHelper.newDomain("foo.tld");
|
||||
Key<HistoryEntry> historyEntryKey = Key.create(Key.create(domain), HistoryEntry.class, 505L);
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setRedemptionHistoryEntry(HistoryEntry.createVKey(historyEntryKey))
|
||||
.build());
|
||||
setEppInput("domain_transfer_request_allocation_token.xml");
|
||||
EppException thrown =
|
||||
assertThrows(AlreadyRedeemedAllocationTokenException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,14 @@ package google.registry.model.domain;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.flows.domain.DomainTransferUtils.createPendingTransferData;
|
||||
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenStatus.NOT_STARTED;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.UNLIMITED_USE;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.insertInDb;
|
||||
import static google.registry.testing.DatabaseHelper.loadByEntity;
|
||||
import static google.registry.testing.DatabaseHelper.loadByKey;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.testing.DatabaseHelper.updateInDb;
|
||||
import static google.registry.testing.SqlHelper.assertThrowForeignKeyViolation;
|
||||
import static google.registry.testing.SqlHelper.saveRegistrar;
|
||||
@@ -31,6 +34,7 @@ import static org.joda.money.CurrencyUnit.USD;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
@@ -44,6 +48,8 @@ import google.registry.model.domain.Period.Unit;
|
||||
import google.registry.model.domain.launch.LaunchNotice;
|
||||
import google.registry.model.domain.rgp.GracePeriodStatus;
|
||||
import google.registry.model.domain.secdns.DelegationSignerData;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.domain.token.AllocationToken.TokenStatus;
|
||||
import google.registry.model.eppcommon.AuthInfo.PasswordAuth;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.eppcommon.Trid;
|
||||
@@ -86,6 +92,7 @@ public class DomainSqlTest {
|
||||
private ContactResource contact;
|
||||
private ContactResource contact2;
|
||||
private ImmutableSet<GracePeriod> gracePeriods;
|
||||
private AllocationToken allocationToken;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
@@ -138,6 +145,24 @@ public class DomainSqlTest {
|
||||
.build();
|
||||
contact = makeContact("contact_id1");
|
||||
contact2 = makeContact("contact_id2");
|
||||
|
||||
allocationToken =
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123Unlimited")
|
||||
.setTokenType(UNLIMITED_USE)
|
||||
.setCreationTimeForTest(DateTime.parse("2010-11-12T05:00:00Z"))
|
||||
.setAllowedTlds(ImmutableSet.of("dev", "app"))
|
||||
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar, NewRegistrar"))
|
||||
.setDiscountFraction(0.5)
|
||||
.setDiscountPremiums(true)
|
||||
.setDiscountYears(3)
|
||||
.setTokenStatusTransitions(
|
||||
ImmutableSortedMap.<DateTime, TokenStatus>naturalOrder()
|
||||
.put(START_OF_TIME, NOT_STARTED)
|
||||
.put(DateTime.now(UTC), TokenStatus.VALID)
|
||||
.put(DateTime.now(UTC).plusWeeks(8), TokenStatus.ENDED)
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -146,12 +171,27 @@ public class DomainSqlTest {
|
||||
assertEqualDomainExcept(loadByKey(domain.createVKey()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDomainBasePersistenceWithCurrentPackageToken() {
|
||||
domain = domain.asBuilder().setCurrentPackageToken(allocationToken.createVKey()).build();
|
||||
persistResource(allocationToken);
|
||||
persistDomain();
|
||||
assertEqualDomainExcept(loadByKey(domain.createVKey()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHostForeignKeyConstraints() {
|
||||
// Persist the domain without the associated host object.
|
||||
assertThrowForeignKeyViolation(() -> insertInDb(contact, contact2, domain));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCurrentPackageTokenForeignKeyConstraints() {
|
||||
// Persist the domain without the associated allocation token object.
|
||||
domain = domain.asBuilder().setCurrentPackageToken(allocationToken.createVKey()).build();
|
||||
assertThrowForeignKeyViolation(() -> persistDomain());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testContactForeignKeyConstraints() {
|
||||
// Persist the domain without the associated contact objects.
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<transfer op="approve">
|
||||
<domain:transfer
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example.tld</domain:name>
|
||||
</domain:transfer>
|
||||
</transfer>
|
||||
<extension>
|
||||
<allocationToken:allocationToken
|
||||
xmlns:allocationToken=
|
||||
"urn:ietf:params:xml:ns:allocationToken-1.0">
|
||||
abc123
|
||||
</allocationToken:allocationToken>
|
||||
</extension>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
||||
@@ -0,0 +1,22 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<transfer op="request">
|
||||
<domain:transfer
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example.tld</domain:name>
|
||||
<domain:period unit="y">1</domain:period>
|
||||
<domain:authInfo>
|
||||
<domain:pw roid="JD1234-REP">2fooBAR</domain:pw>
|
||||
</domain:authInfo>
|
||||
</domain:transfer>
|
||||
</transfer>
|
||||
<extension>
|
||||
<allocationToken:allocationToken
|
||||
xmlns:allocationToken=
|
||||
"urn:ietf:params:xml:ns:allocationToken-1.0">
|
||||
abc123
|
||||
</allocationToken:allocationToken>
|
||||
</extension>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
||||
@@ -106,6 +106,7 @@ class google.registry.model.domain.Domain {
|
||||
google.registry.persistence.VKey<google.registry.model.contact.ContactResource> billingContact;
|
||||
google.registry.persistence.VKey<google.registry.model.contact.ContactResource> registrantContact;
|
||||
google.registry.persistence.VKey<google.registry.model.contact.ContactResource> techContact;
|
||||
google.registry.persistence.VKey<google.registry.model.domain.token.AllocationToken> currentPackageToken;
|
||||
google.registry.persistence.VKey<google.registry.model.poll.PollMessage$Autorenew> autorenewPollMessage;
|
||||
google.registry.persistence.VKey<google.registry.model.poll.PollMessage$OneTime> deletePollMessage;
|
||||
java.lang.String creationClientId;
|
||||
@@ -138,6 +139,7 @@ class google.registry.model.domain.DomainBase {
|
||||
google.registry.persistence.VKey<google.registry.model.contact.ContactResource> billingContact;
|
||||
google.registry.persistence.VKey<google.registry.model.contact.ContactResource> registrantContact;
|
||||
google.registry.persistence.VKey<google.registry.model.contact.ContactResource> techContact;
|
||||
google.registry.persistence.VKey<google.registry.model.domain.token.AllocationToken> currentPackageToken;
|
||||
google.registry.persistence.VKey<google.registry.model.poll.PollMessage$Autorenew> autorenewPollMessage;
|
||||
google.registry.persistence.VKey<google.registry.model.poll.PollMessage$OneTime> deletePollMessage;
|
||||
java.lang.String creationClientId;
|
||||
|
||||
@@ -261,11 +261,11 @@ td.section {
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="property_name">generated on</td>
|
||||
<td class="property_value">2022-07-28 19:22:42.07612</td>
|
||||
<td class="property_value">2022-08-08 20:39:49.590205</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="property_name">last flyway file</td>
|
||||
<td id="lastFlywayFile" class="property_value">V122__add_current_package_token_to_domain.sql</td>
|
||||
<td id="lastFlywayFile" class="property_value">V123__drop_unused_columns_in_billing_cancellation_table.sql</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -274,19 +274,19 @@ td.section {
|
||||
<svg viewbox="0.00 0.00 4029.00 2877.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="erDiagram" style="overflow: hidden; width: 100%; height: 800px"><g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 2873)">
|
||||
<title>SchemaCrawler_Diagram</title>
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-2873 4025,-2873 4025,4 -4,4" />
|
||||
<text text-anchor="start" x="3760.5" y="-29.8" font-family="Helvetica,sans-Serif" font-size="14.00">
|
||||
<text text-anchor="start" x="3752.5" y="-29.8" font-family="Helvetica,sans-Serif" font-size="14.00">
|
||||
generated by
|
||||
</text>
|
||||
<text text-anchor="start" x="3843.5" y="-29.8" font-family="Helvetica,sans-Serif" font-size="14.00">
|
||||
<text text-anchor="start" x="3835.5" y="-29.8" font-family="Helvetica,sans-Serif" font-size="14.00">
|
||||
SchemaCrawler 16.10.1
|
||||
</text>
|
||||
<text text-anchor="start" x="3759.5" y="-10.8" font-family="Helvetica,sans-Serif" font-size="14.00">
|
||||
<text text-anchor="start" x="3751.5" y="-10.8" font-family="Helvetica,sans-Serif" font-size="14.00">
|
||||
generated on
|
||||
</text>
|
||||
<text text-anchor="start" x="3843.5" y="-10.8" font-family="Helvetica,sans-Serif" font-size="14.00">
|
||||
2022-07-28 19:22:42.07612
|
||||
<text text-anchor="start" x="3835.5" y="-10.8" font-family="Helvetica,sans-Serif" font-size="14.00">
|
||||
2022-08-08 20:39:49.590205
|
||||
</text>
|
||||
<polygon fill="none" stroke="#888888" points="3756,-4 3756,-44 4013,-44 4013,-4 3756,-4" /> <!-- allocationtoken_a08ccbef -->
|
||||
<polygon fill="none" stroke="#888888" points="3748,-4 3748,-44 4013,-44 4013,-4 3748,-4" /> <!-- allocationtoken_a08ccbef -->
|
||||
<g id="node1" class="node">
|
||||
<title>allocationtoken_a08ccbef</title>
|
||||
<polygon fill="#ebcef2" stroke="transparent" points="1091.5,-495 1091.5,-514 1277.5,-514 1277.5,-495 1091.5,-495" />
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -120,3 +120,4 @@ V119__token_registration_behavior.sql
|
||||
V120__remove_ofy_key_fields.sql
|
||||
V121__drop_sql_checkpoint_and_txn.sql
|
||||
V122__add_current_package_token_to_domain.sql
|
||||
V123__drop_unused_columns_in_billing_cancellation_table.sql
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
-- Copyright 2022 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.
|
||||
|
||||
ALTER TABLE "BillingCancellation" DROP COLUMN billing_event_domain_repo_id;
|
||||
ALTER TABLE "BillingCancellation" DROP COLUMN billing_event_history_id;
|
||||
ALTER TABLE "BillingCancellation" DROP COLUMN billing_recurrence_domain_repo_id;
|
||||
ALTER TABLE "BillingCancellation" DROP COLUMN billing_recurrence_history_id;
|
||||
|
||||
@@ -272,6 +272,7 @@
|
||||
autorenew_poll_message_id int8,
|
||||
autorenew_poll_message_history_id int8,
|
||||
billing_contact text,
|
||||
current_package_token text,
|
||||
deletion_poll_message_id int8,
|
||||
dns_refresh_request_time timestamptz,
|
||||
domain_name text,
|
||||
@@ -341,6 +342,7 @@
|
||||
autorenew_poll_message_id int8,
|
||||
autorenew_poll_message_history_id int8,
|
||||
billing_contact text,
|
||||
current_package_token text,
|
||||
deletion_poll_message_id int8,
|
||||
dns_refresh_request_time timestamptz,
|
||||
domain_name text,
|
||||
|
||||
@@ -72,11 +72,7 @@ CREATE TABLE public."BillingCancellation" (
|
||||
domain_name text NOT NULL,
|
||||
billing_time timestamp with time zone,
|
||||
billing_event_id bigint,
|
||||
billing_recurrence_id bigint,
|
||||
billing_event_history_id bigint,
|
||||
billing_event_domain_repo_id text,
|
||||
billing_recurrence_history_id bigint,
|
||||
billing_recurrence_domain_repo_id text
|
||||
billing_recurrence_id bigint
|
||||
);
|
||||
|
||||
|
||||
|
||||
@@ -589,12 +589,20 @@ replaced with new ones with the correct approval time.
|
||||
* 2201
|
||||
* The specified resource belongs to another client.
|
||||
* Registrar is not authorized to access this TLD.
|
||||
* The allocation token is invalid.
|
||||
* 2202
|
||||
* Authorization information for accessing resource is invalid.
|
||||
* 2301
|
||||
* The resource does not have a pending transfer.
|
||||
* 2303
|
||||
* Resource with this id does not exist.
|
||||
* 2304
|
||||
* The allocation token is not currently valid.
|
||||
* 2305
|
||||
* The allocation token is not valid for this domain.
|
||||
* The allocation token is not valid for this registrar.
|
||||
* The allocation token is not valid for this TLD.
|
||||
* The allocation token was already redeemed.
|
||||
|
||||
## DomainTransferCancelFlow
|
||||
|
||||
@@ -723,6 +731,7 @@ new ones with the correct approval time).
|
||||
* Registrar is missing the billing account map for this currency type.
|
||||
* Registrar is not authorized to access this TLD.
|
||||
* Registrar must be active in order to perform this operation.
|
||||
* The allocation token is invalid.
|
||||
* 2202
|
||||
* Authorization information for accessing resource is invalid.
|
||||
* 2300
|
||||
@@ -735,6 +744,12 @@ new ones with the correct approval time).
|
||||
extension.
|
||||
* The requested domain name is on the premium price list, and this
|
||||
registrar has blocked premium registrations.
|
||||
* The allocation token is not currently valid.
|
||||
* 2305
|
||||
* The allocation token is not valid for this domain.
|
||||
* The allocation token is not valid for this registrar.
|
||||
* The allocation token is not valid for this TLD.
|
||||
* The allocation token was already redeemed.
|
||||
* 2306
|
||||
* Domain transfer period must be one year.
|
||||
* Domain transfer period must be zero or one year when using the superuser
|
||||
|
||||
Reference in New Issue
Block a user