1
0
mirror of https://github.com/google/nomulus synced 2025-12-23 06:15:42 +00:00

Add unique index for not-deleted domain names (#2853)

This is a backstop against multiple domain creations for the same domain
name getting through
This commit is contained in:
gbrodman
2025-10-24 11:38:23 -04:00
committed by GitHub
parent 0aa6bc6aaa
commit ed25854fbc
12 changed files with 85 additions and 35 deletions

View File

@@ -14,17 +14,19 @@
package google.registry.model;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
import static google.registry.testing.DatabaseHelper.persistActiveHost;
import static google.registry.testing.DatabaseHelper.persistDeletedDomain;
import static google.registry.testing.DatabaseHelper.persistDeletedHost;
import static google.registry.testing.DatabaseHelper.persistDomainAsDeleted;
import static google.registry.testing.DatabaseHelper.persistPremiumList;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.testing.TestDataHelper.loadBytes;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static org.joda.money.CurrencyUnit.USD;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.eppcommon.Trid;
import google.registry.model.host.HostHistory;
@@ -49,7 +51,7 @@ public final class OteStatsTestHelper {
.build());
persistResource(
new DomainHistory.Builder()
.setDomain(persistActiveDomain("example.tld"))
.setDomain(persistActiveDomain("restored.tld"))
.setRegistrarId(oteAccount1)
.setType(Type.DOMAIN_RESTORE)
.setXmlBytes(getBytes("domain_restore.xml"))
@@ -84,7 +86,7 @@ public final class OteStatsTestHelper {
DateTime now = DateTime.now(DateTimeZone.UTC);
persistResource(
new DomainHistory.Builder()
.setDomain(persistActiveDomain("exampleone.tld"))
.setDomain(loadOrCreateDomain("exampleone.tld"))
.setRegistrarId(oteAccount1)
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(getBytes("domain_create_sunrise.xml"))
@@ -92,15 +94,16 @@ public final class OteStatsTestHelper {
.build());
persistResource(
new DomainHistory.Builder()
.setDomain(persistActiveDomain("example-one.tld"))
.setDomain(loadOrCreateDomain("example-one.tld"))
.setRegistrarId(oteAccount1)
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(getBytes("domain_create_claim_notice.xml"))
.setModificationTime(now)
.build());
Domain exampleDomain = loadOrCreateDomain("example.tld");
persistResource(
new DomainHistory.Builder()
.setDomain(persistActiveDomain("example.tld"))
.setDomain(exampleDomain)
.setRegistrarId(oteAccount1)
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(getBytes("domain_create_anchor_tenant_fee_standard.xml"))
@@ -108,7 +111,7 @@ public final class OteStatsTestHelper {
.build());
persistResource(
new DomainHistory.Builder()
.setDomain(persistActiveDomain("example.tld"))
.setDomain(exampleDomain)
.setRegistrarId(oteAccount1)
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(getBytes("domain_create_dsdata.xml"))
@@ -116,7 +119,7 @@ public final class OteStatsTestHelper {
.build());
persistResource(
new DomainHistory.Builder()
.setDomain(persistDeletedDomain("example.tld", now))
.setDomain(persistDomainAsDeleted(loadOrCreateDomain("deleted.tld"), now))
.setRegistrarId(oteAccount1)
.setType(Type.DOMAIN_DELETE)
.setXmlBytes(getBytes("domain_delete.xml"))
@@ -124,7 +127,7 @@ public final class OteStatsTestHelper {
.build());
persistResource(
new DomainHistory.Builder()
.setDomain(persistActiveDomain("example.tld"))
.setDomain(exampleDomain)
.setRegistrarId(oteAccount1)
.setType(Type.DOMAIN_TRANSFER_APPROVE)
.setXmlBytes(getBytes("domain_transfer_approve.xml"))
@@ -132,7 +135,7 @@ public final class OteStatsTestHelper {
.build());
persistResource(
new DomainHistory.Builder()
.setDomain(persistActiveDomain("example.tld"))
.setDomain(exampleDomain)
.setRegistrarId(oteAccount1)
.setType(Type.DOMAIN_TRANSFER_CANCEL)
.setXmlBytes(getBytes("domain_transfer_cancel.xml"))
@@ -140,7 +143,7 @@ public final class OteStatsTestHelper {
.build());
persistResource(
new DomainHistory.Builder()
.setDomain(persistActiveDomain("example.tld"))
.setDomain(exampleDomain)
.setRegistrarId(oteAccount1)
.setType(Type.DOMAIN_TRANSFER_REJECT)
.setXmlBytes(getBytes("domain_transfer_reject.xml"))
@@ -148,7 +151,7 @@ public final class OteStatsTestHelper {
.build());
persistResource(
new DomainHistory.Builder()
.setDomain(persistActiveDomain("example.tld"))
.setDomain(exampleDomain)
.setRegistrarId(oteAccount1)
.setType(Type.DOMAIN_TRANSFER_REQUEST)
.setXmlBytes(getBytes("domain_transfer_request.xml"))
@@ -156,7 +159,7 @@ public final class OteStatsTestHelper {
.build());
persistResource(
new DomainHistory.Builder()
.setDomain(persistActiveDomain("example.tld"))
.setDomain(exampleDomain)
.setRegistrarId(oteAccount1)
.setType(Type.DOMAIN_UPDATE)
.setXmlBytes(getBytes("domain_update_with_secdns.xml"))
@@ -189,4 +192,12 @@ public final class OteStatsTestHelper {
private static byte[] getBytes(String filename) throws IOException {
return loadBytes(OteStatsTestHelper.class, filename).read();
}
private static Domain loadOrCreateDomain(String domainName) {
return tm().transact(
() ->
EppResourceUtils.loadByForeignKey(
Domain.class, domainName, tm().getTransactionTime()))
.orElseGet(() -> persistActiveDomain(domainName));
}
}

View File

@@ -112,6 +112,11 @@ class RdapJsonFormatterTest {
hostNotLinked =
makeAndPersistHost(
"ns5.cat.みんな", null, null, clock.nowUtc().minusYears(5), "unicoderegistrar");
// Create an unused domain that references hostBoth and hostNoAddresses so that
// they will have "associated" (ie, StatusValue.LINKED) status.
Domain dog =
persistResource(
makeDomain("dog.みんな", null, null, null, hostBoth, hostNoAddresses, registrar));
hostSuperordinatePendingTransfer =
persistResource(
makeAndPersistHost(
@@ -119,8 +124,7 @@ class RdapJsonFormatterTest {
.asBuilder()
.setSuperordinateDomain(
persistResource(
makeDomain("dog.みんな", null, null, null, null, null, registrar)
.asBuilder()
dog.asBuilder()
.addStatusValue(StatusValue.PENDING_TRANSFER)
.setTransferData(
new DomainTransferData.Builder()
@@ -150,9 +154,6 @@ class RdapJsonFormatterTest {
.setCreationTimeForTest(clock.nowUtc())
.setLastEppUpdateTime(null)
.build());
// Create an unused domain that references hostBoth and hostNoAddresses so that
// they will have "associated" (ie, StatusValue.LINKED) status.
persistResource(makeDomain("dog.みんな", null, null, null, hostBoth, hostNoAddresses, registrar));
// history entries
// We create 3 "transfer approved" entries, to make sure we only save the last one

View File

@@ -253,7 +253,7 @@ class Spec11EmailUtilsTest {
// Create an inactive domain and an active domain with the same name.
persistResource(loadByEntity(aDomain).asBuilder().addStatusValue(SERVER_HOLD).build());
Host host = persistActiveHost("ns1.example.com");
aDomain = persistDomainWithHost("a.com", host);
aDomain = persistResource(aDomain.asBuilder().setNameservers(host.createVKey()).build());
emailUtils.emailSpec11Reports(
date,

View File

@@ -43,10 +43,14 @@ class DeleteAllocationTokensCommandTest extends CommandTestCase<DeleteAllocation
private AllocationToken preNot2;
private AllocationToken othrRed;
private AllocationToken othrNot;
private Domain exampleDomain;
private Domain foobarDomain;
@BeforeEach
void beforeEach() {
createTlds("foo", "bar");
exampleDomain = persistActiveDomain("example.foo");
foobarDomain = persistActiveDomain("foo.bar");
preRed1 = persistToken("prefix12345AA", null, true);
preRed2 = persistToken("prefixgh8907a", null, true);
preNot1 = persistToken("prefix2978204", null, false);
@@ -97,8 +101,8 @@ class DeleteAllocationTokensCommandTest extends CommandTestCase<DeleteAllocation
@Test
void test_defaultOptions_doesntDeletePerDomainTokens() throws Exception {
AllocationToken preDom1 = persistToken("prefixasdfg897as", "foo.bar", false);
AllocationToken preDom2 = persistToken("prefix98HAZXadbn", "foo.bar", true);
AllocationToken preDom1 = persistToken("prefixasdfg897as", foobarDomain, false);
AllocationToken preDom2 = persistToken("prefix98HAZXadbn", foobarDomain, true);
runCommandForced("--prefix", "prefix");
assertNonexistent(preNot1, preNot2);
assertThat(reloadTokens(preRed1, preRed2, preDom1, preDom2, othrRed, othrNot))
@@ -107,8 +111,8 @@ class DeleteAllocationTokensCommandTest extends CommandTestCase<DeleteAllocation
@Test
void test_withDomains_doesDeletePerDomainTokens() throws Exception {
AllocationToken preDom1 = persistToken("prefixasdfg897as", "foo.bar", false);
AllocationToken preDom2 = persistToken("prefix98HAZXadbn", "foo.bar", true);
AllocationToken preDom1 = persistToken("prefixasdfg897as", foobarDomain, false);
AllocationToken preDom2 = persistToken("prefix98HAZXadbn", foobarDomain, true);
runCommandForced("--prefix", "prefix", "--with_domains");
assertNonexistent(preNot1, preNot2, preDom1);
assertThat(reloadTokens(preRed1, preRed2, preDom2, othrRed, othrNot))
@@ -164,17 +168,15 @@ class DeleteAllocationTokensCommandTest extends CommandTestCase<DeleteAllocation
assertThat(thrown).hasMessageThat().isEqualTo("Provided prefix should not be blank");
}
private static AllocationToken persistToken(
String token, @Nullable String domainName, boolean redeemed) {
private AllocationToken persistToken(String token, @Nullable Domain domain, boolean redeemed) {
AllocationToken.Builder builder =
new AllocationToken.Builder()
.setToken(token)
.setTokenType(SINGLE_USE)
.setDomainName(domainName);
.setDomainName(domain == null ? null : domain.getDomainName());
if (redeemed) {
String domainToPersist = domainName != null ? domainName : "example.foo";
Domain domain = persistActiveDomain(domainToPersist);
HistoryEntryId historyEntryId = new HistoryEntryId(domain.getRepoId(), 1051L);
String repoId = domain == null ? exampleDomain.getRepoId() : domain.getRepoId();
HistoryEntryId historyEntryId = new HistoryEntryId(repoId, 1051L);
builder.setRedemptionHistoryId(historyEntryId);
}
return persistResource(builder.build());

View File

@@ -1,6 +1,6 @@
{
"objectClassName" : "nameserver",
"handle" : "C-ROID",
"handle" : "D-ROID",
"ldhName" : "ns1.dog.xn--q9jyb4c",
"unicodeName" : "ns1.dog.みんな",
"status" : ["active", "pending transfer"],

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 95 KiB