diff --git a/core/src/main/java/google/registry/model/common/CrossTldSingleton.java b/core/src/main/java/google/registry/model/common/CrossTldSingleton.java index 83315bc65..f92b6ba12 100644 --- a/core/src/main/java/google/registry/model/common/CrossTldSingleton.java +++ b/core/src/main/java/google/registry/model/common/CrossTldSingleton.java @@ -20,15 +20,16 @@ import com.googlecode.objectify.Key; import com.googlecode.objectify.annotation.Id; import com.googlecode.objectify.annotation.Parent; import google.registry.model.ImmutableObject; +import javax.persistence.MappedSuperclass; +import javax.persistence.Transient; /** A singleton entity in Datastore. */ +@MappedSuperclass public abstract class CrossTldSingleton extends ImmutableObject { - public static final long SINGLETON_ID = 1; // There is always exactly one of these. + public static final long SINGLETON_ID = 1; // There is always exactly one of these. - @Id - long id = SINGLETON_ID; + @Id @Transient long id = SINGLETON_ID; - @Parent - Key parent = getCrossTldKey(); + @Transient @Parent Key parent = getCrossTldKey(); } diff --git a/core/src/main/java/google/registry/model/server/ServerSecret.java b/core/src/main/java/google/registry/model/server/ServerSecret.java index 7011334f9..290dddf28 100644 --- a/core/src/main/java/google/registry/model/server/ServerSecret.java +++ b/core/src/main/java/google/registry/model/server/ServerSecret.java @@ -14,29 +14,43 @@ package google.registry.model.server; -import static google.registry.model.ofy.ObjectifyService.ofy; +import static google.registry.model.common.EntityGroupRoot.getCrossTldKey; +import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm; +import static google.registry.persistence.transaction.TransactionManagerFactory.ofyTm; import static google.registry.persistence.transaction.TransactionManagerFactory.tm; import com.google.common.annotations.VisibleForTesting; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableList; import com.google.common.primitives.Longs; +import com.googlecode.objectify.Key; import com.googlecode.objectify.annotation.Entity; +import com.googlecode.objectify.annotation.Ignore; +import com.googlecode.objectify.annotation.OnLoad; import com.googlecode.objectify.annotation.Unindex; import google.registry.model.annotations.NotBackedUp; import google.registry.model.annotations.NotBackedUp.Reason; import google.registry.model.common.CrossTldSingleton; +import google.registry.persistence.VKey; +import google.registry.schema.replay.DatastoreEntity; +import google.registry.schema.replay.SqlEntity; import java.nio.ByteBuffer; import java.util.UUID; import java.util.concurrent.ExecutionException; +import javax.persistence.Column; +import javax.persistence.Id; +import javax.persistence.PostLoad; +import javax.persistence.Transient; /** A secret number used for generating tokens (such as XSRF tokens). */ @Entity +@javax.persistence.Entity @Unindex @NotBackedUp(reason = Reason.AUTO_GENERATED) // TODO(b/27427316): Replace this with an entry in KMSKeyring -public class ServerSecret extends CrossTldSingleton { +public class ServerSecret extends CrossTldSingleton implements DatastoreEntity, SqlEntity { /** * Cache of the singleton ServerSecret instance that creates it if not present. @@ -45,28 +59,34 @@ public class ServerSecret extends CrossTldSingleton { * Supplier that can be reset for testing purposes. */ private static final LoadingCache, ServerSecret> CACHE = - CacheBuilder.newBuilder().build( - new CacheLoader, ServerSecret>() { - @Override - public ServerSecret load(Class unused) { - // Fast path - non-transactional load to hit memcache. - ServerSecret secret = ofy().load().entity(new ServerSecret()).now(); - if (secret != null) { - return secret; - } - // Slow path - transactionally create a new ServerSecret (once per app setup). - return tm().transact(() -> { - // Check again for an existing secret within the transaction to avoid races. - ServerSecret secret1 = ofy().load().entity(new ServerSecret()).now(); - if (secret1 == null) { - UUID uuid = UUID.randomUUID(); - secret1 = create(uuid.getMostSignificantBits(), uuid.getLeastSignificantBits()); - ofy().saveWithoutBackup().entity(secret1).now(); + CacheBuilder.newBuilder() + .build( + new CacheLoader, ServerSecret>() { + @Override + public ServerSecret load(Class unused) { + return retrieveAndSaveSecret(); } - return secret1; }); - } - }); + + private static ServerSecret retrieveAndSaveSecret() { + VKey key = + VKey.create( + ServerSecret.class, + SINGLETON_ID, + Key.create(getCrossTldKey(), ServerSecret.class, SINGLETON_ID)); + return tm().transact( + () -> { + // transactionally create a new ServerSecret (once per app setup) if necessary. + // return the ofy() result during Datastore-primary phase + ServerSecret secret = + ofyTm().maybeLoad(key).orElseGet(() -> create(UUID.randomUUID())); + // During a dual-write period, write it to both Datastore and SQL + // even if we didn't have to retrieve it from the DB + ofyTm().transact(() -> ofyTm().putWithoutBackup(secret)); + jpaTm().transact(() -> jpaTm().putWithoutBackup(secret)); + return secret; + }); + } /** Returns the global ServerSecret instance, creating it if one isn't already in Datastore. */ public static ServerSecret get() { @@ -77,23 +97,38 @@ public class ServerSecret extends CrossTldSingleton { } } - /** Most significant 8 bytes of the UUID value. */ - long mostSignificant; + /** Most significant 8 bytes of the UUID value (stored separately for legacy purposes). */ + @Transient long mostSignificant; - /** Least significant 8 bytes of the UUID value. */ - long leastSignificant; + /** Least significant 8 bytes of the UUID value (stored separately for legacy purposes). */ + @Transient long leastSignificant; - @VisibleForTesting - static ServerSecret create(long mostSignificant, long leastSignificant) { - ServerSecret secret = new ServerSecret(); - secret.mostSignificant = mostSignificant; - secret.leastSignificant = leastSignificant; - return secret; + /** The UUID value itself. */ + @Id + @Column(columnDefinition = "uuid") + @Ignore + UUID secret; + + /** Convert the Datastore representation to SQL. */ + @OnLoad + void onLoad() { + secret = new UUID(mostSignificant, leastSignificant); } - /** Returns the value of this ServerSecret as a UUID. */ - public UUID asUuid() { - return new UUID(mostSignificant, leastSignificant); + /** Convert the SQL representation to Datastore. */ + @PostLoad + void postLoad() { + mostSignificant = secret.getMostSignificantBits(); + leastSignificant = secret.getLeastSignificantBits(); + } + + @VisibleForTesting + static ServerSecret create(UUID uuid) { + ServerSecret secret = new ServerSecret(); + secret.mostSignificant = uuid.getMostSignificantBits(); + secret.leastSignificant = uuid.getLeastSignificantBits(); + secret.secret = uuid; + return secret; } /** Returns the value of this ServerSecret as a byte array. */ @@ -104,6 +139,16 @@ public class ServerSecret extends CrossTldSingleton { .array(); } + @Override + public ImmutableList toSqlEntities() { + return ImmutableList.of(); // dually-written + } + + @Override + public ImmutableList toDatastoreEntities() { + return ImmutableList.of(); // dually-written + } + @VisibleForTesting static void resetCache() { CACHE.invalidateAll(); diff --git a/core/src/main/java/google/registry/model/tmch/TmchCrl.java b/core/src/main/java/google/registry/model/tmch/TmchCrl.java index b212167f8..50cf4803d 100644 --- a/core/src/main/java/google/registry/model/tmch/TmchCrl.java +++ b/core/src/main/java/google/registry/model/tmch/TmchCrl.java @@ -15,31 +15,50 @@ package google.registry.model.tmch; import static com.google.common.base.Preconditions.checkNotNull; -import static google.registry.model.ofy.ObjectifyService.ofy; +import static google.registry.model.common.EntityGroupRoot.getCrossTldKey; +import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm; +import static google.registry.persistence.transaction.TransactionManagerFactory.ofyTm; import static google.registry.persistence.transaction.TransactionManagerFactory.tm; +import com.google.common.collect.ImmutableList; +import com.googlecode.objectify.Key; import com.googlecode.objectify.annotation.Entity; import google.registry.model.annotations.NotBackedUp; import google.registry.model.annotations.NotBackedUp.Reason; import google.registry.model.common.CrossTldSingleton; -import javax.annotation.Nullable; +import google.registry.model.tmch.TmchCrl.TmchCrlId; +import google.registry.persistence.VKey; +import google.registry.schema.replay.DatastoreEntity; +import google.registry.schema.replay.SqlEntity; +import java.io.Serializable; +import java.util.Optional; import javax.annotation.concurrent.Immutable; +import javax.persistence.Column; +import javax.persistence.Id; +import javax.persistence.IdClass; import org.joda.time.DateTime; /** Datastore singleton for ICANN's TMCH CA certificate revocation list (CRL). */ @Entity +@javax.persistence.Entity @Immutable @NotBackedUp(reason = Reason.EXTERNALLY_SOURCED) -public final class TmchCrl extends CrossTldSingleton { +@IdClass(TmchCrlId.class) +public final class TmchCrl extends CrossTldSingleton implements DatastoreEntity, SqlEntity { - String crl; - DateTime updated; - String url; + @Id String crl; + + @Id DateTime updated; + + @Id String url; /** Returns the singleton instance of this entity, without memoization. */ - @Nullable - public static TmchCrl get() { - return ofy().load().entity(new TmchCrl()).now(); + public static Optional get() { + VKey key = + VKey.create( + TmchCrl.class, SINGLETON_ID, Key.create(getCrossTldKey(), TmchCrl.class, SINGLETON_ID)); + // return the ofy() result during Datastore-primary phase + return ofyTm().transact(() -> ofyTm().maybeLoad(key)); } /** @@ -47,16 +66,18 @@ public final class TmchCrl extends CrossTldSingleton { * *

Please do not call this function unless your CRL is properly formatted, signed by the root, * and actually newer than the one currently in Datastore. + * + *

During the dual-write period, we write to both Datastore and SQL */ public static void set(final String crl, final String url) { - tm() - .transactNew( + tm().transact( () -> { TmchCrl tmchCrl = new TmchCrl(); tmchCrl.updated = tm().getTransactionTime(); tmchCrl.crl = checkNotNull(crl, "crl"); tmchCrl.url = checkNotNull(url, "url"); - ofy().saveWithoutBackup().entity(tmchCrl); + ofyTm().transactNew(() -> ofyTm().putWithoutBackup(tmchCrl)); + jpaTm().transactNew(() -> jpaTm().putWithoutBackup(tmchCrl)); }); } @@ -74,4 +95,36 @@ public final class TmchCrl extends CrossTldSingleton { public final DateTime getUpdated() { return updated; } + + @Override + public ImmutableList toSqlEntities() { + return ImmutableList.of(); // dually-written + } + + @Override + public ImmutableList toDatastoreEntities() { + return ImmutableList.of(); // dually-written + } + + static class TmchCrlId implements Serializable { + + @Column(name = "certificateRevocations") + String crl; + + @Column(name = "updateTimestamp") + DateTime updated; + + String url; + + /** Hibernate requires this default constructor. */ + private TmchCrlId() {} + + static TmchCrlId create(String crl, DateTime updated, String url) { + TmchCrlId result = new TmchCrlId(); + result.crl = crl; + result.updated = updated; + result.url = url; + return result; + } + } } diff --git a/core/src/main/java/google/registry/tmch/TmchCertificateAuthority.java b/core/src/main/java/google/registry/tmch/TmchCertificateAuthority.java index 422a7a256..6100c0c7b 100644 --- a/core/src/main/java/google/registry/tmch/TmchCertificateAuthority.java +++ b/core/src/main/java/google/registry/tmch/TmchCertificateAuthority.java @@ -32,6 +32,7 @@ import java.security.GeneralSecurityException; import java.security.cert.CertificateParsingException; import java.security.cert.X509CRL; import java.security.cert.X509Certificate; +import java.util.Optional; import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.ThreadSafe; import javax.inject.Inject; @@ -82,14 +83,15 @@ public final class TmchCertificateAuthority { new CacheLoader() { @Override public X509CRL load(final TmchCaMode tmchCaMode) throws GeneralSecurityException { - TmchCrl storedCrl = TmchCrl.get(); - String crlContents; - if (storedCrl == null) { - String file = (tmchCaMode == PILOT) ? CRL_PILOT_FILE : CRL_FILE; - crlContents = readResourceUtf8(TmchCertificateAuthority.class, file); - } else { - crlContents = storedCrl.getCrl(); - } + Optional storedCrl = TmchCrl.get(); + String crlContents = + storedCrl + .map(TmchCrl::getCrl) + .orElseGet( + () -> { + String file = (tmchCaMode == PILOT) ? CRL_PILOT_FILE : CRL_FILE; + return readResourceUtf8(TmchCertificateAuthority.class, file); + }); X509CRL crl = X509Utils.loadCrl(crlContents); crl.verify(ROOT_CERTS.get(tmchCaMode).getPublicKey()); return crl; diff --git a/core/src/main/resources/META-INF/persistence.xml b/core/src/main/resources/META-INF/persistence.xml index 58ab1ec77..4edaed2de 100644 --- a/core/src/main/resources/META-INF/persistence.xml +++ b/core/src/main/resources/META-INF/persistence.xml @@ -63,8 +63,10 @@ google.registry.model.reporting.DomainTransactionRecord google.registry.model.reporting.Spec11ThreatMatch google.registry.model.server.KmsSecretRevision + google.registry.model.server.ServerSecret google.registry.model.smd.SignedMarkRevocationList google.registry.model.tmch.ClaimsListShard + google.registry.model.tmch.TmchCrl google.registry.persistence.transaction.TransactionEntity google.registry.schema.cursor.Cursor google.registry.schema.domain.RegistryLock diff --git a/core/src/test/java/google/registry/model/server/ServerSecretTest.java b/core/src/test/java/google/registry/model/server/ServerSecretTest.java index cc74780e1..7a104d427 100644 --- a/core/src/test/java/google/registry/model/server/ServerSecretTest.java +++ b/core/src/test/java/google/registry/model/server/ServerSecretTest.java @@ -15,21 +15,25 @@ package google.registry.model.server; import static com.google.common.truth.Truth.assertThat; +import static google.registry.model.common.CrossTldSingleton.SINGLETON_ID; +import static google.registry.model.common.EntityGroupRoot.getCrossTldKey; import static google.registry.model.ofy.ObjectifyService.ofy; +import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm; +import com.googlecode.objectify.Key; +import google.registry.model.EntityTestCase; import google.registry.model.ofy.RequestCapturingAsyncDatastoreService; -import google.registry.testing.AppEngineExtension; +import google.registry.persistence.VKey; import java.util.UUID; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; /** Unit tests for {@link ServerSecret}. */ -public class ServerSecretTest { +public class ServerSecretTest extends EntityTestCase { - @RegisterExtension - public final AppEngineExtension appEngine = - AppEngineExtension.builder().withDatastoreAndCloudSql().build(); + ServerSecretTest() { + super(JpaEntityCoverageCheck.ENABLED); + } @BeforeEach void beforeEach() { @@ -41,18 +45,20 @@ public class ServerSecretTest { ServerSecret secret = ServerSecret.get(); assertThat(secret).isNotNull(); assertThat(ofy().load().entity(new ServerSecret()).now()).isEqualTo(secret); + assertThat(loadFromSql()).isEqualTo(secret); } @Test void testGet_existingSecret_returned() { - ServerSecret secret = ServerSecret.create(123, 456); + ServerSecret secret = ServerSecret.create(new UUID(123, 456)); ofy().saveWithoutBackup().entity(secret).now(); assertThat(ServerSecret.get()).isEqualTo(secret); assertThat(ofy().load().entity(new ServerSecret()).now()).isEqualTo(secret); + assertThat(loadFromSql()).isEqualTo(secret); } @Test - void testGet_cachedSecret_returnedWithoutDatastoreRead() { + void testGet_cachedSecret() { int numInitialReads = RequestCapturingAsyncDatastoreService.getReads().size(); ServerSecret secret = ServerSecret.get(); int numReads = RequestCapturingAsyncDatastoreService.getReads().size(); @@ -62,16 +68,28 @@ public class ServerSecretTest { } @Test - void testAsUuid() { - UUID uuid = ServerSecret.create(123, 456).asUuid(); - assertThat(uuid.getMostSignificantBits()).isEqualTo(123); - assertThat(uuid.getLeastSignificantBits()).isEqualTo(456); + void testAsBytes() { + byte[] bytes = ServerSecret.create(new UUID(123, 0x456)).asBytes(); + assertThat(bytes).isEqualTo(new byte[] {0, 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0x4, 0x56}); } - @Test - void testAsBytes() { - byte[] bytes = ServerSecret.create(123, 0x456).asBytes(); - assertThat(bytes) - .isEqualTo(new byte[] {0, 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0x4, 0x56}); + private static ServerSecret loadFromSql() { + return jpaTm() + .transact( + () -> + jpaTm() + .getEntityManager() + .createQuery("FROM ServerSecret", ServerSecret.class) + .setMaxResults(1) + .getResultStream() + .findFirst() + .get()); + } + + private static VKey createKey() { + return VKey.create( + ServerSecret.class, + SINGLETON_ID, + Key.create(getCrossTldKey(), ServerSecret.class, SINGLETON_ID)); } } diff --git a/core/src/test/java/google/registry/model/tmch/TmchCrlTest.java b/core/src/test/java/google/registry/model/tmch/TmchCrlTest.java index 83d1bde55..3f75a5436 100644 --- a/core/src/test/java/google/registry/model/tmch/TmchCrlTest.java +++ b/core/src/test/java/google/registry/model/tmch/TmchCrlTest.java @@ -15,22 +15,48 @@ package google.registry.model.tmch; import static com.google.common.truth.Truth.assertThat; +import static google.registry.model.ofy.ObjectifyService.ofy; +import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm; -import google.registry.testing.AppEngineExtension; +import google.registry.model.EntityTestCase; +import java.util.Optional; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; /** Unit tests for {@link TmchCrl}. */ -public class TmchCrlTest { +public class TmchCrlTest extends EntityTestCase { - @RegisterExtension - public final AppEngineExtension appEngine = - AppEngineExtension.builder().withDatastoreAndCloudSql().build(); + TmchCrlTest() { + super(JpaEntityCoverageCheck.ENABLED); + } @Test void testSuccess() { - assertThat(TmchCrl.get()).isNull(); - TmchCrl.set("lolcat", "http://lol.cat"); - assertThat(TmchCrl.get().getCrl()).isEqualTo("lolcat"); + assertThat(TmchCrl.get()).isEqualTo(Optional.empty()); + TmchCrl.set("lolcat", "https://lol.cat"); + assertThat(TmchCrl.get().get().getCrl()).isEqualTo("lolcat"); + } + + @Test + void testDualWrite() { + TmchCrl expected = new TmchCrl(); + expected.crl = "lolcat"; + expected.url = "https://lol.cat"; + expected.updated = fakeClock.nowUtc(); + TmchCrl.set("lolcat", "https://lol.cat"); + assertThat(ofy().load().entity(new TmchCrl()).now()).isEqualTo(expected); + assertThat(loadFromSql()).isEqualTo(expected); + } + + private static TmchCrl loadFromSql() { + return jpaTm() + .transact( + () -> + jpaTm() + .getEntityManager() + .createQuery("FROM TmchCrl", TmchCrl.class) + .setMaxResults(1) + .getResultStream() + .findFirst() + .get()); } } diff --git a/core/src/test/java/google/registry/request/auth/RequestAuthenticatorTest.java b/core/src/test/java/google/registry/request/auth/RequestAuthenticatorTest.java index e56751820..0cb443cbd 100644 --- a/core/src/test/java/google/registry/request/auth/RequestAuthenticatorTest.java +++ b/core/src/test/java/google/registry/request/auth/RequestAuthenticatorTest.java @@ -43,12 +43,13 @@ import org.junit.jupiter.api.extension.RegisterExtension; /** Unit tests for {@link RequestAuthenticator}. */ class RequestAuthenticatorTest { - @RegisterExtension final AppEngineExtension appEngine = AppEngineExtension.builder().build(); + @RegisterExtension + final AppEngineExtension appEngine = + AppEngineExtension.builder().withDatastoreAndCloudSql().build(); - private static final AuthSettings AUTH_NONE = AuthSettings.create( - ImmutableList.of(AuthMethod.INTERNAL), - AuthLevel.NONE, - UserPolicy.IGNORED); + private static final AuthSettings AUTH_NONE = + AuthSettings.create( + ImmutableList.of(AuthMethod.INTERNAL), AuthLevel.NONE, UserPolicy.IGNORED); private static final AuthSettings AUTH_INTERNAL_OR_ADMIN = AuthSettings.create( ImmutableList.of(AuthMethod.INTERNAL), diff --git a/core/src/test/java/google/registry/schema/integration/SqlIntegrationTestSuite.java b/core/src/test/java/google/registry/schema/integration/SqlIntegrationTestSuite.java index a717bd6f3..59ae333cb 100644 --- a/core/src/test/java/google/registry/schema/integration/SqlIntegrationTestSuite.java +++ b/core/src/test/java/google/registry/schema/integration/SqlIntegrationTestSuite.java @@ -30,8 +30,10 @@ import google.registry.model.registry.RegistryTest; import google.registry.model.registry.label.ReservedListSqlDaoTest; import google.registry.model.reporting.Spec11ThreatMatchTest; import google.registry.model.server.KmsSecretRevisionSqlDaoTest; +import google.registry.model.server.ServerSecretTest; import google.registry.model.smd.SignedMarkRevocationListDaoTest; import google.registry.model.tmch.ClaimsListDaoTest; +import google.registry.model.tmch.TmchCrlTest; import google.registry.persistence.transaction.JpaEntityCoverageExtension; import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageExtension; import google.registry.schema.cursor.CursorDaoTest; @@ -95,8 +97,10 @@ import org.junit.runner.RunWith; RegistryTest.class, ReservedListSqlDaoTest.class, RegistryLockDaoTest.class, + ServerSecretTest.class, SignedMarkRevocationListDaoTest.class, Spec11ThreatMatchTest.class, + TmchCrlTest.class, // AfterSuiteTest must be the last entry. See class javadoc for details. AfterSuiteTest.class }) diff --git a/db/src/main/resources/sql/er_diagram/brief_er_diagram.html b/db/src/main/resources/sql/er_diagram/brief_er_diagram.html index 657d1d06e..4e2791b44 100644 --- a/db/src/main/resources/sql/er_diagram/brief_er_diagram.html +++ b/db/src/main/resources/sql/er_diagram/brief_er_diagram.html @@ -261,19 +261,19 @@ td.section { generated on - 2020-11-04 16:40:52.942256 + 2020-11-09 17:11:19.905881 last flyway file - V72__add_missing_foreign_keys.sql + V73__singleton_entities.sql

 

 

- + SchemaCrawler_Diagram - + generated by @@ -284,7 +284,7 @@ td.section { generated on - 2020-11-04 16:40:52.942256 + 2020-11-09 17:11:19.905881 @@ -1352,7 +1352,7 @@ td.section { fk_domain_transfer_losing_registrar_id - + tld_f1fa57e2 @@ -2956,97 +2956,153 @@ td.section { fkgq03rk0bt1hb915dnyvd3vnfc - + + serversecret_6cc90f09 + + + public.ServerSecret + + + + [table] + + + secret + + + + + uuid not null + + + + signedmarkrevocationentry_99c39721 - - + + public.SignedMarkRevocationEntry - - + + [table] - + revision_id - + - + int8 not null - + smd_id - + - + text not null - + - + signedmarkrevocationlist_c5d968fb - - + + public.SignedMarkRevocationList - - + + [table] - + revision_id - + - + bigserial not null - + - + auto-incremented - + signedmarkrevocationentry_99c39721:w->signedmarkrevocationlist_c5d968fb:e - - - - - - - - + + + + + + + + fk5ivlhvs3121yx2li5tqh54u4 - - - transaction_d50389d4 - - - public.Transaction + + + tmchcrl_d282355 + + + public.TmchCrl - - + + [table] - + + certificate_revocations + + + + + text not null + + + update_timestamp + + + + + timestamptz not null + + + url + + + + + text not null + + + + + transaction_d50389d4 + + + public.Transaction + + + + [table] + + id - + - + bigserial not null - + - + auto-incremented - + @@ -6461,6 +6517,36 @@ td.section {

 

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
public.ServerSecret [table] +
secretuuid not null
Primary Key
ServerSecret_pkey[primary key]
secret
+

 

@@ -6741,6 +6827,56 @@ td.section {
public.SignedMarkRevocationEntry [table]

 

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
public.TmchCrl [table] +
certificate_revocationstext not null
update_timestamptimestamptz not null
urltext not null
Primary Key
TmchCrl_pkey[primary key]
certificate_revocations
update_timestamp
url
+

 

diff --git a/db/src/main/resources/sql/er_diagram/full_er_diagram.html b/db/src/main/resources/sql/er_diagram/full_er_diagram.html index 0c7224a31..b7c709b60 100644 --- a/db/src/main/resources/sql/er_diagram/full_er_diagram.html +++ b/db/src/main/resources/sql/er_diagram/full_er_diagram.html @@ -261,32 +261,32 @@ td.section { - + - +
public.Transaction [table]
generated on2020-11-04 16:40:50.9033912020-11-09 17:11:18.25328
last flyway fileV72__add_missing_foreign_keys.sqlV73__singleton_entities.sql

 

 

- + SchemaCrawler_Diagram - - + + generated by - + SchemaCrawler 16.10.1 - + generated on - - 2020-11-04 16:40:50.903391 + + 2020-11-09 17:11:18.25328 - + allocationtoken_a08ccbef @@ -1577,7 +1577,7 @@ td.section { billingevent_a57d1815:w->registrar_6e1503e3:e - + @@ -3048,7 +3048,7 @@ td.section { fk_domain_transfer_losing_registrar_id - + tld_f1fa57e2 @@ -5124,7 +5124,7 @@ td.section { - + fk_spec11_threat_match_tld @@ -5385,14 +5385,14 @@ td.section { domaintransactionrecord_6e77ff61:w->tld_f1fa57e2:e - + - - - - - + + + + + fk_domain_transaction_record_tld @@ -6068,121 +6068,177 @@ td.section { fkgq03rk0bt1hb915dnyvd3vnfc - + + serversecret_6cc90f09 + + + public.ServerSecret + + + + [table] + + + secret + + + + + uuid not null + + + + signedmarkrevocationentry_99c39721 - - + + public.SignedMarkRevocationEntry - - + + [table] - + revision_id - + - + int8 not null - + revocation_time - + - + timestamptz not null - + smd_id - + - + text not null - + - + signedmarkrevocationlist_c5d968fb - - + + public.SignedMarkRevocationList - - + + [table] - + revision_id - + - + bigserial not null - + - + auto-incremented - + creation_time - + - + timestamptz - + signedmarkrevocationentry_99c39721:w->signedmarkrevocationlist_c5d968fb:e - - - - - - - - + + + + + + + + fk5ivlhvs3121yx2li5tqh54u4 - - - transaction_d50389d4 - - - public.Transaction + + + tmchcrl_d282355 + + + public.TmchCrl - - + + [table] - + + certificate_revocations + + + + + text not null + + + update_timestamp + + + + + timestamptz not null + + + url + + + + + text not null + + + + + transaction_d50389d4 + + + public.Transaction + + + + [table] + + id - + - + bigserial not null - + - + auto-incremented - + contents - + - + bytea - + @@ -12531,6 +12587,54 @@ td.section {

 

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
public.ServerSecret [table] +
secretuuid not null
Primary Key
ServerSecret_pkey[primary key]
secret
Indexes
ServerSecret_pkey[unique index]
secretascending
+

 

@@ -13129,6 +13233,84 @@ td.section {
public.SignedMarkRevocationEntry [table]

 

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
public.TmchCrl [table] +
certificate_revocationstext not null
update_timestamptimestamptz not null
urltext not null
Primary Key
TmchCrl_pkey[primary key]
certificate_revocations
update_timestamp
url
Indexes
TmchCrl_pkey[unique index]
certificate_revocationsascending
update_timestampascending
urlascending
+

 

diff --git a/db/src/main/resources/sql/flyway.txt b/db/src/main/resources/sql/flyway.txt index 6e1602c67..cd6151565 100644 --- a/db/src/main/resources/sql/flyway.txt +++ b/db/src/main/resources/sql/flyway.txt @@ -70,3 +70,4 @@ V69__change_primary_key_and_add_history_table_for_delegation_signer.sql V70__signed_mark_revocation_list.sql V71__create_kms_secret.sql V72__add_missing_foreign_keys.sql +V73__singleton_entities.sql diff --git a/db/src/main/resources/sql/flyway/V73__singleton_entities.sql b/db/src/main/resources/sql/flyway/V73__singleton_entities.sql new file mode 100644 index 000000000..08e735770 --- /dev/null +++ b/db/src/main/resources/sql/flyway/V73__singleton_entities.sql @@ -0,0 +1,25 @@ +-- Copyright 2020 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. + +CREATE TABLE "ServerSecret" ( + secret uuid NOT NULL, + PRIMARY KEY (secret) +); + +CREATE TABLE "TmchCrl" ( + certificate_revocations text NOT NULL, + update_timestamp timestamptz NOT NULL, + url text NOT NULL, + PRIMARY KEY (certificate_revocations, update_timestamp, url) +); diff --git a/db/src/main/resources/sql/schema/db-schema.sql.generated b/db/src/main/resources/sql/schema/db-schema.sql.generated index 1bdd0556d..25f6a3c0e 100644 --- a/db/src/main/resources/sql/schema/db-schema.sql.generated +++ b/db/src/main/resources/sql/schema/db-schema.sql.generated @@ -626,6 +626,11 @@ primary key (revision_id) ); + create table "ServerSecret" ( + secret uuid not null, + primary key (secret) + ); + create table "SignedMarkRevocationEntry" ( revision_id int8 not null, revocation_time timestamptz not null, @@ -692,6 +697,13 @@ primary key (tld_name) ); + create table "TmchCrl" ( + certificate_revocations text not null, + update_timestamp timestamptz not null, + url text not null, + primary key (certificate_revocations, update_timestamp, url) + ); + create table "Transaction" ( id bigserial not null, contents bytea, diff --git a/db/src/main/resources/sql/schema/nomulus.golden.sql b/db/src/main/resources/sql/schema/nomulus.golden.sql index e95350d55..ae0637542 100644 --- a/db/src/main/resources/sql/schema/nomulus.golden.sql +++ b/db/src/main/resources/sql/schema/nomulus.golden.sql @@ -899,6 +899,15 @@ CREATE SEQUENCE public."SafeBrowsingThreat_id_seq" ALTER SEQUENCE public."SafeBrowsingThreat_id_seq" OWNED BY public."Spec11ThreatMatch".id; +-- +-- Name: ServerSecret; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public."ServerSecret" ( + secret uuid NOT NULL +); + + -- -- Name: SignedMarkRevocationEntry; Type: TABLE; Schema: public; Owner: - -- @@ -985,6 +994,17 @@ CREATE TABLE public."Tld" ( ); +-- +-- Name: TmchCrl; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public."TmchCrl" ( + certificate_revocations text NOT NULL, + update_timestamp timestamp with time zone NOT NULL, + url text NOT NULL +); + + -- -- Name: Transaction; Type: TABLE; Schema: public; Owner: - -- @@ -1302,6 +1322,14 @@ ALTER TABLE ONLY public."Spec11ThreatMatch" ADD CONSTRAINT "SafeBrowsingThreat_pkey" PRIMARY KEY (id); +-- +-- Name: ServerSecret ServerSecret_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public."ServerSecret" + ADD CONSTRAINT "ServerSecret_pkey" PRIMARY KEY (secret); + + -- -- Name: SignedMarkRevocationEntry SignedMarkRevocationEntry_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -1326,6 +1354,14 @@ ALTER TABLE ONLY public."Tld" ADD CONSTRAINT "Tld_pkey" PRIMARY KEY (tld_name); +-- +-- Name: TmchCrl TmchCrl_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public."TmchCrl" + ADD CONSTRAINT "TmchCrl_pkey" PRIMARY KEY (certificate_revocations, update_timestamp, url); + + -- -- Name: Transaction Transaction_pkey; Type: CONSTRAINT; Schema: public; Owner: - --
public.Transaction [table]