diff --git a/core/src/main/java/google/registry/tools/DomainLockUtils.java b/core/src/main/java/google/registry/tools/DomainLockUtils.java index c2374118b..cd47f10c0 100644 --- a/core/src/main/java/google/registry/tools/DomainLockUtils.java +++ b/core/src/main/java/google/registry/tools/DomainLockUtils.java @@ -37,6 +37,7 @@ import javax.annotation.Nullable; import javax.inject.Inject; import javax.inject.Named; import org.joda.time.DateTime; +import org.joda.time.Duration; /** * Utility functions for validating and applying {@link RegistryLock}s. @@ -76,12 +77,12 @@ public final class DomainLockUtils { *

The unlock will not be applied until {@link #verifyAndApplyUnlock} is called. */ public RegistryLock saveNewRegistryUnlockRequest( - String domainName, String registrarId, boolean isAdmin) { + String domainName, String registrarId, boolean isAdmin, Optional relockDuration) { return jpaTm() .transact( () -> RegistryLockDao.save( - createUnlockBuilder(domainName, registrarId, isAdmin).build())); + createUnlockBuilder(domainName, registrarId, isAdmin, relockDuration).build())); } /** Verifies and applies the lock request previously requested by a user. */ @@ -166,14 +167,14 @@ public final class DomainLockUtils { * Nomulus tool commands. */ public RegistryLock administrativelyApplyUnlock( - String domainName, String registrarId, boolean isAdmin) { + String domainName, String registrarId, boolean isAdmin, Optional relockDuration) { return jpaTm() .transact( () -> { DateTime now = jpaTm().getTransactionTime(); RegistryLock result = RegistryLockDao.save( - createUnlockBuilder(domainName, registrarId, isAdmin) + createUnlockBuilder(domainName, registrarId, isAdmin, relockDuration) .setUnlockCompletionTimestamp(now) .build()); tm().transact(() -> removeLockStatuses(result, isAdmin, now)); @@ -217,7 +218,7 @@ public final class DomainLockUtils { } private RegistryLock.Builder createUnlockBuilder( - String domainName, String registrarId, boolean isAdmin) { + String domainName, String registrarId, boolean isAdmin, Optional relockDuration) { DateTime now = jpaTm().getTransactionTime(); DomainBase domainBase = getDomain(domainName, now); Optional lockOptional = @@ -258,6 +259,7 @@ public final class DomainLockUtils { !lock.isSuperuser(), "Non-admin user cannot unlock admin-locked domain %s", domainName); newLockBuilder = lock.asBuilder(); } + relockDuration.ifPresent(newLockBuilder::setRelockDuration); return newLockBuilder .setVerificationCode(stringGenerator.createString(VERIFICATION_CODE_LENGTH)) .isSuperuser(isAdmin) diff --git a/core/src/main/java/google/registry/tools/UnlockDomainCommand.java b/core/src/main/java/google/registry/tools/UnlockDomainCommand.java index fa07df0cc..49a1ac508 100644 --- a/core/src/main/java/google/registry/tools/UnlockDomainCommand.java +++ b/core/src/main/java/google/registry/tools/UnlockDomainCommand.java @@ -22,6 +22,7 @@ import com.google.common.collect.Sets; import com.google.common.flogger.FluentLogger; import google.registry.model.domain.DomainBase; import google.registry.model.eppcommon.StatusValue; +import java.util.Optional; import org.joda.time.DateTime; /** @@ -53,6 +54,6 @@ public class UnlockDomainCommand extends LockOrUnlockDomainCommand { @Override protected void createAndApplyRequest(String domain) { - domainLockUtils.administrativelyApplyUnlock(domain, clientId, true); + domainLockUtils.administrativelyApplyUnlock(domain, clientId, true, Optional.empty()); } } diff --git a/core/src/main/java/google/registry/ui/server/registrar/RegistryLockPostAction.java b/core/src/main/java/google/registry/ui/server/registrar/RegistryLockPostAction.java index eb42ca3d3..effbc4aba 100644 --- a/core/src/main/java/google/registry/ui/server/registrar/RegistryLockPostAction.java +++ b/core/src/main/java/google/registry/ui/server/registrar/RegistryLockPostAction.java @@ -56,6 +56,7 @@ import javax.inject.Inject; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import org.apache.http.client.utils.URIBuilder; +import org.joda.time.Duration; /** * UI action that allows for creating registry locks. Locks / unlocks must be verified separately @@ -141,7 +142,8 @@ public class RegistryLockPostAction implements Runnable, JsonActionRunner.JsonAc : domainLockUtils.saveNewRegistryUnlockRequest( postInput.fullyQualifiedDomainName, postInput.clientId, - registrarAccessor.isAdmin()); + registrarAccessor.isAdmin(), + Optional.ofNullable(postInput.relockDurationMillis).map(Duration::new)); sendVerificationEmail(registryLock, userEmail, postInput.isLock); }); String action = postInput.isLock ? "lock" : "unlock"; @@ -218,5 +220,6 @@ public class RegistryLockPostAction implements Runnable, JsonActionRunner.JsonAc private String fullyQualifiedDomainName; private Boolean isLock; private String password; + private Long relockDurationMillis; } } diff --git a/core/src/test/java/google/registry/batch/RelockDomainActionTest.java b/core/src/test/java/google/registry/batch/RelockDomainActionTest.java index a5bcbcb35..f8137d69d 100644 --- a/core/src/test/java/google/registry/batch/RelockDomainActionTest.java +++ b/core/src/test/java/google/registry/batch/RelockDomainActionTest.java @@ -40,6 +40,7 @@ import google.registry.testing.FakeResponse; import google.registry.testing.UserInfo; import google.registry.tools.DomainLockUtils; import google.registry.util.StringGenerator.Alphabets; +import java.util.Optional; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -79,7 +80,9 @@ public class RelockDomainActionTest { oldLock = domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, CLIENT_ID, POC_ID, false); assertThat(reloadDomain(domain).getStatusValues()) .containsAtLeastElementsIn(REGISTRY_LOCK_STATUSES); - oldLock = domainLockUtils.administrativelyApplyUnlock(DOMAIN_NAME, CLIENT_ID, false); + oldLock = + domainLockUtils.administrativelyApplyUnlock( + DOMAIN_NAME, CLIENT_ID, false, Optional.empty()); assertThat(reloadDomain(domain).getStatusValues()).containsNoneIn(REGISTRY_LOCK_STATUSES); action = createAction(oldLock.getRevisionId()); } diff --git a/core/src/test/java/google/registry/tools/DomainLockUtilsTest.java b/core/src/test/java/google/registry/tools/DomainLockUtilsTest.java index 4892c1cd9..dfc03722b 100644 --- a/core/src/test/java/google/registry/tools/DomainLockUtilsTest.java +++ b/core/src/test/java/google/registry/tools/DomainLockUtilsTest.java @@ -42,6 +42,7 @@ import google.registry.testing.DeterministicStringGenerator; import google.registry.testing.FakeClock; import google.registry.testing.UserInfo; import google.registry.util.StringGenerator.Alphabets; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import org.joda.time.Duration; @@ -91,7 +92,8 @@ public final class DomainLockUtilsTest { public void testSuccess_createUnlock() { domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", POC_ID, false); RegistryLock lock = - domainLockUtils.saveNewRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", false); + domainLockUtils.saveNewRegistryUnlockRequest( + DOMAIN_NAME, "TheRegistrar", false, Optional.empty()); assertThat(lock.getUnlockCompletionTimestamp().isPresent()).isFalse(); } @@ -99,7 +101,8 @@ public final class DomainLockUtilsTest { public void testSuccess_createUnlock_adminUnlockingAdmin() { domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", null, true); RegistryLock lock = - domainLockUtils.saveNewRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", true); + domainLockUtils.saveNewRegistryUnlockRequest( + DOMAIN_NAME, "TheRegistrar", true, Optional.empty()); assertThat(lock.getUnlockCompletionTimestamp().isPresent()).isFalse(); } @@ -116,10 +119,12 @@ public final class DomainLockUtilsTest { @Test public void testSuccess_createUnlock_previousUnlockRequestExpired() { domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", POC_ID, false); - domainLockUtils.saveNewRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", false); + domainLockUtils.saveNewRegistryUnlockRequest( + DOMAIN_NAME, "TheRegistrar", false, Optional.empty()); clock.advanceBy(Duration.standardDays(1)); RegistryLock unlockRequest = - domainLockUtils.saveNewRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", false); + domainLockUtils.saveNewRegistryUnlockRequest( + DOMAIN_NAME, "TheRegistrar", false, Optional.empty()); domainLockUtils.verifyAndApplyUnlock(unlockRequest.getVerificationCode(), false); assertThat(reloadDomain().getStatusValues()).containsNoneIn(REGISTRY_LOCK_STATUSES); } @@ -136,7 +141,8 @@ public final class DomainLockUtilsTest { public void testSuccess_applyUnlockDomain() { domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", POC_ID, false); RegistryLock unlock = - domainLockUtils.saveNewRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", false); + domainLockUtils.saveNewRegistryUnlockRequest( + DOMAIN_NAME, "TheRegistrar", false, Optional.empty()); domainLockUtils.verifyAndApplyUnlock(unlock.getVerificationCode(), false); verifyProperlyUnlockedDomain(false); } @@ -155,7 +161,8 @@ public final class DomainLockUtilsTest { domainLockUtils.saveNewRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", null, true); domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), true); RegistryLock unlock = - domainLockUtils.saveNewRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", true); + domainLockUtils.saveNewRegistryUnlockRequest( + DOMAIN_NAME, "TheRegistrar", true, Optional.empty()); domainLockUtils.verifyAndApplyUnlock(unlock.getVerificationCode(), true); verifyProperlyUnlockedDomain(true); } @@ -178,7 +185,8 @@ public final class DomainLockUtilsTest { RegistryLock lock = domainLockUtils.saveNewRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false); domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false); - domainLockUtils.administrativelyApplyUnlock(DOMAIN_NAME, "TheRegistrar", false); + domainLockUtils.administrativelyApplyUnlock( + DOMAIN_NAME, "TheRegistrar", false, Optional.empty()); verifyProperlyUnlockedDomain(false); } @@ -187,7 +195,8 @@ public final class DomainLockUtilsTest { RegistryLock lock = domainLockUtils.saveNewRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", null, true); domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), true); - domainLockUtils.administrativelyApplyUnlock(DOMAIN_NAME, "TheRegistrar", true); + domainLockUtils.administrativelyApplyUnlock( + DOMAIN_NAME, "TheRegistrar", true, Optional.empty()); verifyProperlyUnlockedDomain(true); } @@ -195,7 +204,8 @@ public final class DomainLockUtilsTest { public void testSuccess_regularLock_relockSet() { domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", POC_ID, false); RegistryLock oldLock = - domainLockUtils.administrativelyApplyUnlock(DOMAIN_NAME, "TheRegistrar", false); + domainLockUtils.administrativelyApplyUnlock( + DOMAIN_NAME, "TheRegistrar", false, Optional.empty()); RegistryLock newLock = domainLockUtils.saveNewRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false); newLock = domainLockUtils.verifyAndApplyLock(newLock.getVerificationCode(), false); @@ -208,7 +218,8 @@ public final class DomainLockUtilsTest { public void testSuccess_administrativelyLock_relockSet() { domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", POC_ID, false); RegistryLock oldLock = - domainLockUtils.administrativelyApplyUnlock(DOMAIN_NAME, "TheRegistrar", false); + domainLockUtils.administrativelyApplyUnlock( + DOMAIN_NAME, "TheRegistrar", false, Optional.empty()); RegistryLock newLock = domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", POC_ID, false); assertThat( @@ -216,19 +227,29 @@ public final class DomainLockUtilsTest { .isEqualTo(newLock.getRevisionId()); } + @Test + public void testSuccess_createUnlock_relockDuration() { + domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", POC_ID, false); + RegistryLock lock = + domainLockUtils.saveNewRegistryUnlockRequest( + DOMAIN_NAME, "TheRegistrar", false, Optional.of(Duration.standardDays(1))); + assertThat(lock.getRelockDuration()).isEqualTo(Optional.of(Duration.standardDays(1))); + } + @Test public void testFailure_createUnlock_alreadyPendingUnlock() { RegistryLock lock = domainLockUtils.saveNewRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false); domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false); - domainLockUtils.saveNewRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", false); + domainLockUtils.saveNewRegistryUnlockRequest( + DOMAIN_NAME, "TheRegistrar", false, Optional.empty()); assertThat( assertThrows( IllegalArgumentException.class, () -> domainLockUtils.saveNewRegistryUnlockRequest( - DOMAIN_NAME, "TheRegistrar", false))) + DOMAIN_NAME, "TheRegistrar", false, Optional.empty()))) .hasMessageThat() .isEqualTo("A pending unlock action already exists for example.tld"); } @@ -243,7 +264,7 @@ public final class DomainLockUtilsTest { IllegalArgumentException.class, () -> domainLockUtils.saveNewRegistryUnlockRequest( - DOMAIN_NAME, "TheRegistrar", false))) + DOMAIN_NAME, "TheRegistrar", false, Optional.empty()))) .hasMessageThat() .isEqualTo("Non-admin user cannot unlock admin-locked domain example.tld"); } @@ -293,7 +314,7 @@ public final class DomainLockUtilsTest { IllegalArgumentException.class, () -> domainLockUtils.saveNewRegistryUnlockRequest( - DOMAIN_NAME, "TheRegistrar", false))) + DOMAIN_NAME, "TheRegistrar", false, Optional.empty()))) .hasMessageThat() .isEqualTo("Domain example.tld is already unlocked"); } @@ -346,7 +367,8 @@ public final class DomainLockUtilsTest { domainLockUtils.saveNewRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false); domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false); RegistryLock unlock = - domainLockUtils.saveNewRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", false); + domainLockUtils.saveNewRegistryUnlockRequest( + DOMAIN_NAME, "TheRegistrar", false, Optional.empty()); domainLockUtils.verifyAndApplyUnlock(unlock.getVerificationCode(), false); assertThat( diff --git a/core/src/test/java/google/registry/ui/server/registrar/RegistryLockPostActionTest.java b/core/src/test/java/google/registry/ui/server/registrar/RegistryLockPostActionTest.java index 06eb224af..bc0c3e4c5 100644 --- a/core/src/test/java/google/registry/ui/server/registrar/RegistryLockPostActionTest.java +++ b/core/src/test/java/google/registry/ui/server/registrar/RegistryLockPostActionTest.java @@ -20,6 +20,7 @@ import static google.registry.testing.DatastoreHelper.createTld; import static google.registry.testing.DatastoreHelper.loadRegistrar; import static google.registry.testing.DatastoreHelper.newDomainBase; import static google.registry.testing.DatastoreHelper.persistResource; +import static google.registry.testing.SqlHelper.getMostRecentRegistryLockByRepoId; import static google.registry.testing.SqlHelper.getRegistryLockByVerificationCode; import static google.registry.testing.SqlHelper.saveRegistryLock; import static google.registry.tools.LockOrUnlockDomainCommand.REGISTRY_LOCK_STATUSES; @@ -49,9 +50,11 @@ import google.registry.util.EmailMessage; import google.registry.util.SendEmailService; import google.registry.util.StringGenerator.Alphabets; import java.util.Map; +import java.util.Optional; import java.util.UUID; import javax.mail.internet.InternetAddress; import javax.servlet.http.HttpServletResponse; +import org.joda.time.Duration; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -116,6 +119,22 @@ public final class RegistryLockPostActionTest { assertSuccess(response, "unlock", "Marla.Singer.RegistryLock@crr.com"); } + @Test + public void testSuccess_unlock_relockDurationSet() throws Exception { + saveRegistryLock(createLock().asBuilder().setLockCompletionTimestamp(clock.nowUtc()).build()); + persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build()); + ImmutableMap request = + new ImmutableMap.Builder() + .putAll(unlockRequest()) + .put("relockDurationMillis", Duration.standardDays(1).getMillis()) + .build(); + Map response = action.handleJsonRequest(request); + assertSuccess(response, "unlock", "Marla.Singer@crr.com"); + RegistryLock savedUnlockRequest = getMostRecentRegistryLockByRepoId(domain.getRepoId()).get(); + assertThat(savedUnlockRequest.getRelockDuration()) + .isEqualTo(Optional.of(Duration.standardDays(1))); + } + @Test public void testSuccess_unlock_adminUnlockingAdmin() throws Exception { saveRegistryLock(