Absorb `DeletedAccounts` into `Accounts`
This commit is contained in:
		
							parent
							
								
									9945367fa1
								
							
						
					
					
						commit
						1b9bf01ab1
					
				|  | @ -176,7 +176,6 @@ import org.whispersystems.textsecuregcm.storage.AccountsManager; | ||||||
| import org.whispersystems.textsecuregcm.storage.ChangeNumberManager; | import org.whispersystems.textsecuregcm.storage.ChangeNumberManager; | ||||||
| import org.whispersystems.textsecuregcm.storage.ClientReleaseManager; | import org.whispersystems.textsecuregcm.storage.ClientReleaseManager; | ||||||
| import org.whispersystems.textsecuregcm.storage.ClientReleases; | import org.whispersystems.textsecuregcm.storage.ClientReleases; | ||||||
| import org.whispersystems.textsecuregcm.storage.DeletedAccounts; |  | ||||||
| import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager; | import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager; | ||||||
| import org.whispersystems.textsecuregcm.storage.IssuedReceiptsManager; | import org.whispersystems.textsecuregcm.storage.IssuedReceiptsManager; | ||||||
| import org.whispersystems.textsecuregcm.storage.KeysManager; | import org.whispersystems.textsecuregcm.storage.KeysManager; | ||||||
|  | @ -299,9 +298,6 @@ public class WhisperServerService extends Application<WhisperServerConfiguration | ||||||
|     DynamoDbClient dynamoDbClient = DynamoDbFromConfig.client(config.getDynamoDbClientConfiguration(), |     DynamoDbClient dynamoDbClient = DynamoDbFromConfig.client(config.getDynamoDbClientConfiguration(), | ||||||
|         AWSSDK_CREDENTIALS_PROVIDER); |         AWSSDK_CREDENTIALS_PROVIDER); | ||||||
| 
 | 
 | ||||||
|     DeletedAccounts deletedAccounts = new DeletedAccounts(dynamoDbClient, |  | ||||||
|         config.getDynamoDbTables().getDeletedAccounts().getTableName()); |  | ||||||
| 
 |  | ||||||
|     DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager = |     DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager = | ||||||
|         new DynamicConfigurationManager<>(config.getAppConfig().getApplication(), |         new DynamicConfigurationManager<>(config.getAppConfig().getApplication(), | ||||||
|             config.getAppConfig().getEnvironment(), |             config.getAppConfig().getEnvironment(), | ||||||
|  | @ -325,6 +321,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration | ||||||
|         config.getDynamoDbTables().getAccounts().getPhoneNumberTableName(), |         config.getDynamoDbTables().getAccounts().getPhoneNumberTableName(), | ||||||
|         config.getDynamoDbTables().getAccounts().getPhoneNumberIdentifierTableName(), |         config.getDynamoDbTables().getAccounts().getPhoneNumberIdentifierTableName(), | ||||||
|         config.getDynamoDbTables().getAccounts().getUsernamesTableName(), |         config.getDynamoDbTables().getAccounts().getUsernamesTableName(), | ||||||
|  |         config.getDynamoDbTables().getDeletedAccounts().getTableName(), | ||||||
|         config.getDynamoDbTables().getAccounts().getScanPageSize()); |         config.getDynamoDbTables().getAccounts().getScanPageSize()); | ||||||
|     ClientReleases clientReleases = new ClientReleases(dynamoDbAsyncClient, |     ClientReleases clientReleases = new ClientReleases(dynamoDbAsyncClient, | ||||||
|         config.getDynamoDbTables().getClientReleases().getTableName()); |         config.getDynamoDbTables().getClientReleases().getTableName()); | ||||||
|  | @ -514,7 +511,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration | ||||||
|     AccountLockManager accountLockManager = new AccountLockManager(dynamoDbClient, |     AccountLockManager accountLockManager = new AccountLockManager(dynamoDbClient, | ||||||
|         config.getDynamoDbTables().getDeletedAccountsLock().getTableName()); |         config.getDynamoDbTables().getDeletedAccountsLock().getTableName()); | ||||||
|     AccountsManager accountsManager = new AccountsManager(accounts, phoneNumberIdentifiers, cacheCluster, |     AccountsManager accountsManager = new AccountsManager(accounts, phoneNumberIdentifiers, cacheCluster, | ||||||
|         accountLockManager, deletedAccounts, keys, messagesManager, profilesManager, |         accountLockManager, keys, messagesManager, profilesManager, | ||||||
|         secureStorageClient, secureBackupClient, secureValueRecovery2Client, |         secureStorageClient, secureBackupClient, secureValueRecovery2Client, | ||||||
|         clientPresenceManager, |         clientPresenceManager, | ||||||
|         experimentEnrollmentManager, registrationRecoveryPasswordsManager, clock); |         experimentEnrollmentManager, registrationRecoveryPasswordsManager, clock); | ||||||
|  | @ -764,7 +761,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration | ||||||
|         new DonationController(clock, zkReceiptOperations, redeemedReceiptsManager, accountsManager, config.getBadges(), |         new DonationController(clock, zkReceiptOperations, redeemedReceiptsManager, accountsManager, config.getBadges(), | ||||||
|             ReceiptCredentialPresentation::new), |             ReceiptCredentialPresentation::new), | ||||||
|         new MessageController(rateLimiters, messageByteLimitCardinalityEstimator, messageSender, receiptSender, |         new MessageController(rateLimiters, messageByteLimitCardinalityEstimator, messageSender, receiptSender, | ||||||
|             accountsManager, deletedAccounts, messagesManager, pushNotificationManager, reportMessageManager, |             accountsManager, messagesManager, pushNotificationManager, reportMessageManager, | ||||||
|             multiRecipientMessageExecutor, messageDeliveryScheduler, reportSpamTokenProvider, clientReleaseManager, |             multiRecipientMessageExecutor, messageDeliveryScheduler, reportSpamTokenProvider, clientReleaseManager, | ||||||
|             dynamicConfigurationManager), |             dynamicConfigurationManager), | ||||||
|         new PaymentsController(currencyManager, paymentsCredentialsGenerator), |         new PaymentsController(currencyManager, paymentsCredentialsGenerator), | ||||||
|  |  | ||||||
|  | @ -99,7 +99,6 @@ import org.whispersystems.textsecuregcm.spam.ReportSpamTokenProvider; | ||||||
| import org.whispersystems.textsecuregcm.storage.Account; | import org.whispersystems.textsecuregcm.storage.Account; | ||||||
| import org.whispersystems.textsecuregcm.storage.AccountsManager; | import org.whispersystems.textsecuregcm.storage.AccountsManager; | ||||||
| import org.whispersystems.textsecuregcm.storage.ClientReleaseManager; | import org.whispersystems.textsecuregcm.storage.ClientReleaseManager; | ||||||
| import org.whispersystems.textsecuregcm.storage.DeletedAccounts; |  | ||||||
| import org.whispersystems.textsecuregcm.storage.Device; | import org.whispersystems.textsecuregcm.storage.Device; | ||||||
| import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager; | import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager; | ||||||
| import org.whispersystems.textsecuregcm.storage.MessagesManager; | import org.whispersystems.textsecuregcm.storage.MessagesManager; | ||||||
|  | @ -123,7 +122,6 @@ public class MessageController { | ||||||
|   private final MessageSender messageSender; |   private final MessageSender messageSender; | ||||||
|   private final ReceiptSender receiptSender; |   private final ReceiptSender receiptSender; | ||||||
|   private final AccountsManager accountsManager; |   private final AccountsManager accountsManager; | ||||||
|   private final DeletedAccounts deletedAccounts; |  | ||||||
|   private final MessagesManager messagesManager; |   private final MessagesManager messagesManager; | ||||||
|   private final PushNotificationManager pushNotificationManager; |   private final PushNotificationManager pushNotificationManager; | ||||||
|   private final ReportMessageManager reportMessageManager; |   private final ReportMessageManager reportMessageManager; | ||||||
|  | @ -159,7 +157,6 @@ public class MessageController { | ||||||
|       MessageSender messageSender, |       MessageSender messageSender, | ||||||
|       ReceiptSender receiptSender, |       ReceiptSender receiptSender, | ||||||
|       AccountsManager accountsManager, |       AccountsManager accountsManager, | ||||||
|       DeletedAccounts deletedAccounts, |  | ||||||
|       MessagesManager messagesManager, |       MessagesManager messagesManager, | ||||||
|       PushNotificationManager pushNotificationManager, |       PushNotificationManager pushNotificationManager, | ||||||
|       ReportMessageManager reportMessageManager, |       ReportMessageManager reportMessageManager, | ||||||
|  | @ -173,7 +170,6 @@ public class MessageController { | ||||||
|     this.messageSender = messageSender; |     this.messageSender = messageSender; | ||||||
|     this.receiptSender = receiptSender; |     this.receiptSender = receiptSender; | ||||||
|     this.accountsManager = accountsManager; |     this.accountsManager = accountsManager; | ||||||
|     this.deletedAccounts = deletedAccounts; |  | ||||||
|     this.messagesManager = messagesManager; |     this.messagesManager = messagesManager; | ||||||
|     this.pushNotificationManager = pushNotificationManager; |     this.pushNotificationManager = pushNotificationManager; | ||||||
|     this.reportMessageManager = reportMessageManager; |     this.reportMessageManager = reportMessageManager; | ||||||
|  | @ -628,7 +624,7 @@ public class MessageController { | ||||||
|         sourceAci = maybeAccount.map(Account::getUuid); |         sourceAci = maybeAccount.map(Account::getUuid); | ||||||
|         sourcePni = maybeAccount.map(Account::getPhoneNumberIdentifier); |         sourcePni = maybeAccount.map(Account::getPhoneNumberIdentifier); | ||||||
|       } else { |       } else { | ||||||
|         sourceAci = deletedAccounts.findUuid(source); |         sourceAci = accountsManager.findRecentlyDeletedAccountIdentifier(source); | ||||||
|         sourcePni = Optional.ofNullable(accountsManager.getPhoneNumberIdentifier(source)); |         sourcePni = Optional.ofNullable(accountsManager.getPhoneNumberIdentifier(source)); | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|  | @ -638,7 +634,7 @@ public class MessageController { | ||||||
| 
 | 
 | ||||||
|       if (sourceAccount.isEmpty()) { |       if (sourceAccount.isEmpty()) { | ||||||
|         logger.warn("Could not find source: {}", sourceAci.get()); |         logger.warn("Could not find source: {}", sourceAci.get()); | ||||||
|         sourceNumber = deletedAccounts.findE164(sourceAci.get()); |         sourceNumber = accountsManager.findRecentlyDeletedE164(sourceAci.get()); | ||||||
|         sourcePni = sourceNumber.map(accountsManager::getPhoneNumberIdentifier); |         sourcePni = sourceNumber.map(accountsManager::getPhoneNumberIdentifier); | ||||||
|       } else { |       } else { | ||||||
|         sourceNumber = sourceAccount.map(Account::getNumber); |         sourceNumber = sourceAccount.map(Account::getNumber); | ||||||
|  |  | ||||||
|  | @ -15,10 +15,12 @@ public class AccountLockManager { | ||||||
| 
 | 
 | ||||||
|   private final AmazonDynamoDBLockClient lockClient; |   private final AmazonDynamoDBLockClient lockClient; | ||||||
| 
 | 
 | ||||||
|  |   static final String KEY_ACCOUNT_E164 = "P"; | ||||||
|  | 
 | ||||||
|   public AccountLockManager(final DynamoDbClient lockDynamoDb, final String lockTableName) { |   public AccountLockManager(final DynamoDbClient lockDynamoDb, final String lockTableName) { | ||||||
|     this(new AmazonDynamoDBLockClient( |     this(new AmazonDynamoDBLockClient( | ||||||
|         AmazonDynamoDBLockClientOptions.builder(lockDynamoDb, lockTableName) |         AmazonDynamoDBLockClientOptions.builder(lockDynamoDb, lockTableName) | ||||||
|             .withPartitionKeyName(DeletedAccounts.KEY_ACCOUNT_E164) |             .withPartitionKeyName(KEY_ACCOUNT_E164) | ||||||
|             .withLeaseDuration(15L) |             .withLeaseDuration(15L) | ||||||
|             .withHeartbeatPeriod(2L) |             .withHeartbeatPeriod(2L) | ||||||
|             .withTimeUnit(TimeUnit.SECONDS) |             .withTimeUnit(TimeUnit.SECONDS) | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ import java.io.IOException; | ||||||
| import java.nio.ByteBuffer; | import java.nio.ByteBuffer; | ||||||
| import java.time.Clock; | import java.time.Clock; | ||||||
| import java.time.Duration; | import java.time.Duration; | ||||||
|  | import java.time.Instant; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.HashMap; | import java.util.HashMap; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | @ -48,9 +49,11 @@ import software.amazon.awssdk.services.dynamodb.model.AttributeValue; | ||||||
| import software.amazon.awssdk.services.dynamodb.model.CancellationReason; | import software.amazon.awssdk.services.dynamodb.model.CancellationReason; | ||||||
| import software.amazon.awssdk.services.dynamodb.model.ConditionalCheckFailedException; | import software.amazon.awssdk.services.dynamodb.model.ConditionalCheckFailedException; | ||||||
| import software.amazon.awssdk.services.dynamodb.model.Delete; | import software.amazon.awssdk.services.dynamodb.model.Delete; | ||||||
|  | import software.amazon.awssdk.services.dynamodb.model.DeleteItemRequest; | ||||||
| import software.amazon.awssdk.services.dynamodb.model.GetItemRequest; | import software.amazon.awssdk.services.dynamodb.model.GetItemRequest; | ||||||
| import software.amazon.awssdk.services.dynamodb.model.GetItemResponse; | import software.amazon.awssdk.services.dynamodb.model.GetItemResponse; | ||||||
| import software.amazon.awssdk.services.dynamodb.model.Put; | import software.amazon.awssdk.services.dynamodb.model.Put; | ||||||
|  | import software.amazon.awssdk.services.dynamodb.model.PutItemRequest; | ||||||
| import software.amazon.awssdk.services.dynamodb.model.QueryRequest; | import software.amazon.awssdk.services.dynamodb.model.QueryRequest; | ||||||
| import software.amazon.awssdk.services.dynamodb.model.QueryResponse; | import software.amazon.awssdk.services.dynamodb.model.QueryResponse; | ||||||
| import software.amazon.awssdk.services.dynamodb.model.ReturnValuesOnConditionCheckFailure; | import software.amazon.awssdk.services.dynamodb.model.ReturnValuesOnConditionCheckFailure; | ||||||
|  | @ -124,18 +127,23 @@ public class Accounts extends AbstractDynamoDbStore { | ||||||
|   // time to live; number |   // time to live; number | ||||||
|   static final String ATTR_TTL = "TTL"; |   static final String ATTR_TTL = "TTL"; | ||||||
| 
 | 
 | ||||||
|  |   static final String DELETED_ACCOUNTS_KEY_ACCOUNT_E164 = "P"; | ||||||
|  |   static final String DELETED_ACCOUNTS_ATTR_ACCOUNT_UUID = "U"; | ||||||
|  |   static final String DELETED_ACCOUNTS_ATTR_EXPIRES = "E"; | ||||||
|  |   static final String DELETED_ACCOUNTS_UUID_TO_E164_INDEX_NAME = "u_to_p"; | ||||||
|  | 
 | ||||||
|   static final String USERNAME_LINK_TO_UUID_INDEX = "ul_to_u"; |   static final String USERNAME_LINK_TO_UUID_INDEX = "ul_to_u"; | ||||||
| 
 | 
 | ||||||
|  |   static final Duration DELETED_ACCOUNTS_TIME_TO_LIVE = Duration.ofDays(30); | ||||||
|  | 
 | ||||||
|   private final Clock clock; |   private final Clock clock; | ||||||
| 
 | 
 | ||||||
|   private final DynamoDbAsyncClient asyncClient; |   private final DynamoDbAsyncClient asyncClient; | ||||||
| 
 | 
 | ||||||
|   private final String phoneNumberConstraintTableName; |   private final String phoneNumberConstraintTableName; | ||||||
| 
 |  | ||||||
|   private final String phoneNumberIdentifierConstraintTableName; |   private final String phoneNumberIdentifierConstraintTableName; | ||||||
| 
 |  | ||||||
|   private final String usernamesConstraintTableName; |   private final String usernamesConstraintTableName; | ||||||
| 
 |   private final String deletedAccountsTableName; | ||||||
|   private final String accountsTableName; |   private final String accountsTableName; | ||||||
| 
 | 
 | ||||||
|   private final int scanPageSize; |   private final int scanPageSize; | ||||||
|  | @ -150,6 +158,7 @@ public class Accounts extends AbstractDynamoDbStore { | ||||||
|       final String phoneNumberConstraintTableName, |       final String phoneNumberConstraintTableName, | ||||||
|       final String phoneNumberIdentifierConstraintTableName, |       final String phoneNumberIdentifierConstraintTableName, | ||||||
|       final String usernamesConstraintTableName, |       final String usernamesConstraintTableName, | ||||||
|  |       final String deletedAccountsTableName, | ||||||
|       final int scanPageSize) { |       final int scanPageSize) { | ||||||
|     super(client); |     super(client); | ||||||
|     this.clock = clock; |     this.clock = clock; | ||||||
|  | @ -158,6 +167,7 @@ public class Accounts extends AbstractDynamoDbStore { | ||||||
|     this.phoneNumberIdentifierConstraintTableName = phoneNumberIdentifierConstraintTableName; |     this.phoneNumberIdentifierConstraintTableName = phoneNumberIdentifierConstraintTableName; | ||||||
|     this.accountsTableName = accountsTableName; |     this.accountsTableName = accountsTableName; | ||||||
|     this.usernamesConstraintTableName = usernamesConstraintTableName; |     this.usernamesConstraintTableName = usernamesConstraintTableName; | ||||||
|  |     this.deletedAccountsTableName = deletedAccountsTableName; | ||||||
|     this.scanPageSize = scanPageSize; |     this.scanPageSize = scanPageSize; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -168,10 +178,11 @@ public class Accounts extends AbstractDynamoDbStore { | ||||||
|       final String phoneNumberConstraintTableName, |       final String phoneNumberConstraintTableName, | ||||||
|       final String phoneNumberIdentifierConstraintTableName, |       final String phoneNumberIdentifierConstraintTableName, | ||||||
|       final String usernamesConstraintTableName, |       final String usernamesConstraintTableName, | ||||||
|  |       final String deletedAccountsTableName, | ||||||
|       final int scanPageSize) { |       final int scanPageSize) { | ||||||
|     this(Clock.systemUTC(), client, asyncClient, accountsTableName, |     this(Clock.systemUTC(), client, asyncClient, accountsTableName, | ||||||
|         phoneNumberConstraintTableName, phoneNumberIdentifierConstraintTableName, usernamesConstraintTableName, |         phoneNumberConstraintTableName, phoneNumberIdentifierConstraintTableName, usernamesConstraintTableName, | ||||||
|         scanPageSize); |         deletedAccountsTableName, scanPageSize); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public boolean create(final Account account) { |   public boolean create(final Account account) { | ||||||
|  | @ -706,6 +717,23 @@ public class Accounts extends AbstractDynamoDbStore { | ||||||
|             .map(Accounts::fromItem))); |             .map(Accounts::fromItem))); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   public void putRecentlyDeletedAccount(final UUID uuid, final String e164) { | ||||||
|  |     db().putItem(PutItemRequest.builder() | ||||||
|  |         .tableName(deletedAccountsTableName) | ||||||
|  |         .item(Map.of( | ||||||
|  |             DELETED_ACCOUNTS_KEY_ACCOUNT_E164, AttributeValues.fromString(e164), | ||||||
|  |             DELETED_ACCOUNTS_ATTR_ACCOUNT_UUID, AttributeValues.fromUUID(uuid), | ||||||
|  |             DELETED_ACCOUNTS_ATTR_EXPIRES, AttributeValues.fromLong(Instant.now().plus(DELETED_ACCOUNTS_TIME_TO_LIVE).getEpochSecond()))) | ||||||
|  |         .build()); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public void removeRecentlyDeletedAccount(final String e164) { | ||||||
|  |     db().deleteItem(DeleteItemRequest.builder() | ||||||
|  |         .tableName(deletedAccountsTableName) | ||||||
|  |         .key(Map.of(DELETED_ACCOUNTS_KEY_ACCOUNT_E164, AttributeValues.fromString(e164))) | ||||||
|  |         .build()); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   @Nonnull |   @Nonnull | ||||||
|   public CompletableFuture<Optional<Account>> getByAccountIdentifierAsync(final UUID uuid) { |   public CompletableFuture<Optional<Account>> getByAccountIdentifierAsync(final UUID uuid) { | ||||||
|     return AsyncTimerUtil.record(GET_BY_UUID_TIMER, () -> itemByKeyAsync(accountsTableName, KEY_ACCOUNT_UUID, AttributeValues.fromUUID(uuid)) |     return AsyncTimerUtil.record(GET_BY_UUID_TIMER, () -> itemByKeyAsync(accountsTableName, KEY_ACCOUNT_UUID, AttributeValues.fromUUID(uuid)) | ||||||
|  | @ -713,6 +741,37 @@ public class Accounts extends AbstractDynamoDbStore { | ||||||
|         .toCompletableFuture(); |         .toCompletableFuture(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   public Optional<UUID> findRecentlyDeletedAccountIdentifier(final String e164) { | ||||||
|  |     final GetItemResponse response = db().getItem(GetItemRequest.builder() | ||||||
|  |         .tableName(deletedAccountsTableName) | ||||||
|  |         .consistentRead(true) | ||||||
|  |         .key(Map.of(DELETED_ACCOUNTS_KEY_ACCOUNT_E164, AttributeValues.fromString(e164))) | ||||||
|  |         .build()); | ||||||
|  | 
 | ||||||
|  |     return Optional.ofNullable(AttributeValues.getUUID(response.item(), DELETED_ACCOUNTS_ATTR_ACCOUNT_UUID, null)); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public Optional<String> findRecentlyDeletedE164(final UUID uuid) { | ||||||
|  |     final QueryResponse response = db().query(QueryRequest.builder() | ||||||
|  |         .tableName(deletedAccountsTableName) | ||||||
|  |         .indexName(DELETED_ACCOUNTS_UUID_TO_E164_INDEX_NAME) | ||||||
|  |         .keyConditionExpression("#uuid = :uuid") | ||||||
|  |         .projectionExpression("#e164") | ||||||
|  |         .expressionAttributeNames(Map.of("#uuid", DELETED_ACCOUNTS_ATTR_ACCOUNT_UUID, | ||||||
|  |             "#e164", DELETED_ACCOUNTS_KEY_ACCOUNT_E164)) | ||||||
|  |         .expressionAttributeValues(Map.of(":uuid", AttributeValues.fromUUID(uuid))).build()); | ||||||
|  | 
 | ||||||
|  |     if (response.count() == 0) { | ||||||
|  |       return Optional.empty(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (response.count() > 1) { | ||||||
|  |       throw new RuntimeException("Impossible result: more than one phone number returned for UUID: " + uuid); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return Optional.ofNullable(response.items().get(0).get(DELETED_ACCOUNTS_KEY_ACCOUNT_E164).s()); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   public void delete(final UUID uuid) { |   public void delete(final UUID uuid) { | ||||||
|     DELETE_TIMER.record(() -> getByAccountIdentifier(uuid).ifPresent(account -> { |     DELETE_TIMER.record(() -> getByAccountIdentifier(uuid).ifPresent(account -> { | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -101,7 +101,6 @@ public class AccountsManager { | ||||||
|   private final PhoneNumberIdentifiers phoneNumberIdentifiers; |   private final PhoneNumberIdentifiers phoneNumberIdentifiers; | ||||||
|   private final FaultTolerantRedisCluster cacheCluster; |   private final FaultTolerantRedisCluster cacheCluster; | ||||||
|   private final AccountLockManager accountLockManager; |   private final AccountLockManager accountLockManager; | ||||||
|   private final DeletedAccounts deletedAccounts; |  | ||||||
|   private final KeysManager keysManager; |   private final KeysManager keysManager; | ||||||
|   private final MessagesManager messagesManager; |   private final MessagesManager messagesManager; | ||||||
|   private final ProfilesManager profilesManager; |   private final ProfilesManager profilesManager; | ||||||
|  | @ -147,7 +146,6 @@ public class AccountsManager { | ||||||
|       final PhoneNumberIdentifiers phoneNumberIdentifiers, |       final PhoneNumberIdentifiers phoneNumberIdentifiers, | ||||||
|       final FaultTolerantRedisCluster cacheCluster, |       final FaultTolerantRedisCluster cacheCluster, | ||||||
|       final AccountLockManager accountLockManager, |       final AccountLockManager accountLockManager, | ||||||
|       final DeletedAccounts deletedAccounts, |  | ||||||
|       final KeysManager keysManager, |       final KeysManager keysManager, | ||||||
|       final MessagesManager messagesManager, |       final MessagesManager messagesManager, | ||||||
|       final ProfilesManager profilesManager, |       final ProfilesManager profilesManager, | ||||||
|  | @ -162,7 +160,6 @@ public class AccountsManager { | ||||||
|     this.phoneNumberIdentifiers = phoneNumberIdentifiers; |     this.phoneNumberIdentifiers = phoneNumberIdentifiers; | ||||||
|     this.cacheCluster = cacheCluster; |     this.cacheCluster = cacheCluster; | ||||||
|     this.accountLockManager = accountLockManager; |     this.accountLockManager = accountLockManager; | ||||||
|     this.deletedAccounts = deletedAccounts; |  | ||||||
|     this.keysManager = keysManager; |     this.keysManager = keysManager; | ||||||
|     this.messagesManager = messagesManager; |     this.messagesManager = messagesManager; | ||||||
|     this.profilesManager = profilesManager; |     this.profilesManager = profilesManager; | ||||||
|  | @ -201,7 +198,7 @@ public class AccountsManager { | ||||||
| 
 | 
 | ||||||
|         // Reuse the ACI from any recently-deleted account with this number to cover cases where somebody is |         // Reuse the ACI from any recently-deleted account with this number to cover cases where somebody is | ||||||
|         // re-registering. |         // re-registering. | ||||||
|         account.setUuid(deletedAccounts.findUuid(number).orElseGet(UUID::randomUUID)); |         account.setUuid(accounts.findRecentlyDeletedAccountIdentifier(number).orElseGet(UUID::randomUUID)); | ||||||
|         account.addDevice(device); |         account.addDevice(device); | ||||||
|         account.setRegistrationLockFromAttributes(accountAttributes); |         account.setRegistrationLockFromAttributes(accountAttributes); | ||||||
|         account.setUnidentifiedAccessKey(accountAttributes.getUnidentifiedAccessKey()); |         account.setUnidentifiedAccessKey(accountAttributes.getUnidentifiedAccessKey()); | ||||||
|  | @ -261,7 +258,7 @@ public class AccountsManager { | ||||||
| 
 | 
 | ||||||
|         // Clear any "recently deleted account" record for this number since, if it existed, we've used its old ACI for |         // Clear any "recently deleted account" record for this number since, if it existed, we've used its old ACI for | ||||||
|         // the newly-created account. |         // the newly-created account. | ||||||
|         deletedAccounts.remove(number); |         accounts.removeRecentlyDeletedAccount(number); | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
|       return account; |       return account; | ||||||
|  | @ -303,7 +300,7 @@ public class AccountsManager { | ||||||
|       //    of the account changing its number (which facilitates ACI consistency in cases that a party is switching |       //    of the account changing its number (which facilitates ACI consistency in cases that a party is switching | ||||||
|       //    back and forth between numbers). |       //    back and forth between numbers). | ||||||
|       // 3. No account with the target number exists at all, in which case no additional action is needed. |       // 3. No account with the target number exists at all, in which case no additional action is needed. | ||||||
|       final Optional<UUID> recentlyDeletedAci = deletedAccounts.findUuid(targetNumber); |       final Optional<UUID> recentlyDeletedAci = accounts.findRecentlyDeletedAccountIdentifier(targetNumber); | ||||||
|       final Optional<Account> maybeExistingAccount = getByE164(targetNumber); |       final Optional<Account> maybeExistingAccount = getByE164(targetNumber); | ||||||
|       final Optional<UUID> maybeDisplacedUuid; |       final Optional<UUID> maybeDisplacedUuid; | ||||||
| 
 | 
 | ||||||
|  | @ -314,7 +311,7 @@ public class AccountsManager { | ||||||
|         maybeDisplacedUuid = recentlyDeletedAci; |         maybeDisplacedUuid = recentlyDeletedAci; | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       maybeDisplacedUuid.ifPresent(displacedUuid -> deletedAccounts.put(displacedUuid, originalNumber)); |       maybeDisplacedUuid.ifPresent(displacedUuid -> accounts.putRecentlyDeletedAccount(displacedUuid, originalNumber)); | ||||||
| 
 | 
 | ||||||
|       final UUID uuid = account.getUuid(); |       final UUID uuid = account.getUuid(); | ||||||
|       final UUID phoneNumberIdentifier = phoneNumberIdentifiers.getPhoneNumberIdentifier(targetNumber); |       final UUID phoneNumberIdentifier = phoneNumberIdentifiers.getPhoneNumberIdentifier(targetNumber); | ||||||
|  | @ -836,6 +833,14 @@ public class AccountsManager { | ||||||
|     return phoneNumberIdentifiers.getPhoneNumberIdentifier(e164); |     return phoneNumberIdentifiers.getPhoneNumberIdentifier(e164); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   public Optional<UUID> findRecentlyDeletedAccountIdentifier(final String e164) { | ||||||
|  |     return accounts.findRecentlyDeletedAccountIdentifier(e164); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public Optional<String> findRecentlyDeletedE164(final UUID uuid) { | ||||||
|  |     return accounts.findRecentlyDeletedE164(uuid); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   public AccountCrawlChunk getAllFromDynamo(int length) { |   public AccountCrawlChunk getAllFromDynamo(int length) { | ||||||
|     return accounts.getAllFromStart(length); |     return accounts.getAllFromStart(length); | ||||||
|   } |   } | ||||||
|  | @ -856,7 +861,7 @@ public class AccountsManager { | ||||||
| 
 | 
 | ||||||
|         delete(account); |         delete(account); | ||||||
| 
 | 
 | ||||||
|         deletedAccounts.put(accountIdentifier, e164); |         accounts.putRecentlyDeletedAccount(accountIdentifier, e164); | ||||||
|       }); |       }); | ||||||
|     } catch (final RuntimeException | InterruptedException e) { |     } catch (final RuntimeException | InterruptedException e) { | ||||||
|       logger.warn("Failed to delete account", e); |       logger.warn("Failed to delete account", e); | ||||||
|  |  | ||||||
|  | @ -1,87 +0,0 @@ | ||||||
| /* |  | ||||||
|  * Copyright 2013-2021 Signal Messenger, LLC |  | ||||||
|  * SPDX-License-Identifier: AGPL-3.0-only |  | ||||||
|  */ |  | ||||||
| package org.whispersystems.textsecuregcm.storage; |  | ||||||
| 
 |  | ||||||
| import java.time.Duration; |  | ||||||
| import java.time.Instant; |  | ||||||
| import java.util.Map; |  | ||||||
| import java.util.Optional; |  | ||||||
| import java.util.UUID; |  | ||||||
| import org.whispersystems.textsecuregcm.util.AttributeValues; |  | ||||||
| import software.amazon.awssdk.services.dynamodb.DynamoDbClient; |  | ||||||
| import software.amazon.awssdk.services.dynamodb.model.DeleteItemRequest; |  | ||||||
| import software.amazon.awssdk.services.dynamodb.model.GetItemRequest; |  | ||||||
| import software.amazon.awssdk.services.dynamodb.model.GetItemResponse; |  | ||||||
| import software.amazon.awssdk.services.dynamodb.model.PutItemRequest; |  | ||||||
| import software.amazon.awssdk.services.dynamodb.model.QueryRequest; |  | ||||||
| import software.amazon.awssdk.services.dynamodb.model.QueryResponse; |  | ||||||
| 
 |  | ||||||
| public class DeletedAccounts { |  | ||||||
| 
 |  | ||||||
|   // e164, primary key |  | ||||||
|   static final String KEY_ACCOUNT_E164 = "P"; |  | ||||||
|   static final String ATTR_ACCOUNT_UUID = "U"; |  | ||||||
|   static final String ATTR_EXPIRES = "E"; |  | ||||||
| 
 |  | ||||||
|   static final String UUID_TO_E164_INDEX_NAME = "u_to_p"; |  | ||||||
| 
 |  | ||||||
|   static final Duration TIME_TO_LIVE = Duration.ofDays(30); |  | ||||||
| 
 |  | ||||||
|   private final DynamoDbClient dynamoDbClient; |  | ||||||
|   private final String tableName; |  | ||||||
| 
 |  | ||||||
|   public DeletedAccounts(final DynamoDbClient dynamoDbClient, final String tableName) { |  | ||||||
|     this.dynamoDbClient = dynamoDbClient; |  | ||||||
|     this.tableName = tableName; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public void put(UUID uuid, String e164) { |  | ||||||
|     dynamoDbClient.putItem(PutItemRequest.builder() |  | ||||||
|         .tableName(tableName) |  | ||||||
|         .item(Map.of( |  | ||||||
|             KEY_ACCOUNT_E164, AttributeValues.fromString(e164), |  | ||||||
|             ATTR_ACCOUNT_UUID, AttributeValues.fromUUID(uuid), |  | ||||||
|             ATTR_EXPIRES, AttributeValues.fromLong(Instant.now().plus(TIME_TO_LIVE).getEpochSecond()))) |  | ||||||
|         .build()); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public Optional<UUID> findUuid(final String e164) { |  | ||||||
|     final GetItemResponse response = dynamoDbClient.getItem(GetItemRequest.builder() |  | ||||||
|         .tableName(tableName) |  | ||||||
|         .consistentRead(true) |  | ||||||
|         .key(Map.of(KEY_ACCOUNT_E164, AttributeValues.fromString(e164))) |  | ||||||
|         .build()); |  | ||||||
| 
 |  | ||||||
|     return Optional.ofNullable(AttributeValues.getUUID(response.item(), ATTR_ACCOUNT_UUID, null)); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public Optional<String> findE164(final UUID uuid) { |  | ||||||
|     final QueryResponse response = dynamoDbClient.query(QueryRequest.builder() |  | ||||||
|         .tableName(tableName) |  | ||||||
|         .indexName(UUID_TO_E164_INDEX_NAME) |  | ||||||
|         .keyConditionExpression("#uuid = :uuid") |  | ||||||
|         .projectionExpression("#e164") |  | ||||||
|         .expressionAttributeNames(Map.of("#uuid", ATTR_ACCOUNT_UUID, |  | ||||||
|             "#e164", KEY_ACCOUNT_E164)) |  | ||||||
|         .expressionAttributeValues(Map.of(":uuid", AttributeValues.fromUUID(uuid))).build()); |  | ||||||
| 
 |  | ||||||
|     if (response.count() == 0) { |  | ||||||
|       return Optional.empty(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (response.count() > 1) { |  | ||||||
|       throw new RuntimeException("Impossible result: more than one phone number returned for UUID: " + uuid); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return Optional.ofNullable(response.items().get(0).get(KEY_ACCOUNT_E164).s()); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public void remove(final String e164) { |  | ||||||
|     dynamoDbClient.deleteItem(DeleteItemRequest.builder() |  | ||||||
|         .tableName(tableName) |  | ||||||
|         .key(Map.of(KEY_ACCOUNT_E164, AttributeValues.fromString(e164))) |  | ||||||
|         .build()); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  | @ -38,7 +38,6 @@ import org.whispersystems.textsecuregcm.storage.Account; | ||||||
| import org.whispersystems.textsecuregcm.storage.AccountLockManager; | import org.whispersystems.textsecuregcm.storage.AccountLockManager; | ||||||
| import org.whispersystems.textsecuregcm.storage.Accounts; | import org.whispersystems.textsecuregcm.storage.Accounts; | ||||||
| import org.whispersystems.textsecuregcm.storage.AccountsManager; | import org.whispersystems.textsecuregcm.storage.AccountsManager; | ||||||
| import org.whispersystems.textsecuregcm.storage.DeletedAccounts; |  | ||||||
| import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager; | import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager; | ||||||
| import org.whispersystems.textsecuregcm.storage.KeysManager; | import org.whispersystems.textsecuregcm.storage.KeysManager; | ||||||
| import org.whispersystems.textsecuregcm.storage.MessagesCache; | import org.whispersystems.textsecuregcm.storage.MessagesCache; | ||||||
|  | @ -141,8 +140,6 @@ public class AssignUsernameCommand extends EnvironmentCommand<WhisperServerConfi | ||||||
|     DynamoDbClient dynamoDbClient = DynamoDbFromConfig.client(configuration.getDynamoDbClientConfiguration(), |     DynamoDbClient dynamoDbClient = DynamoDbFromConfig.client(configuration.getDynamoDbClientConfiguration(), | ||||||
|         WhisperServerService.AWSSDK_CREDENTIALS_PROVIDER); |         WhisperServerService.AWSSDK_CREDENTIALS_PROVIDER); | ||||||
| 
 | 
 | ||||||
|     DeletedAccounts deletedAccounts = new DeletedAccounts(dynamoDbClient, |  | ||||||
|         configuration.getDynamoDbTables().getDeletedAccounts().getTableName()); |  | ||||||
|     RegistrationRecoveryPasswords registrationRecoveryPasswords = new RegistrationRecoveryPasswords( |     RegistrationRecoveryPasswords registrationRecoveryPasswords = new RegistrationRecoveryPasswords( | ||||||
|         configuration.getDynamoDbTables().getRegistrationRecovery().getTableName(), |         configuration.getDynamoDbTables().getRegistrationRecovery().getTableName(), | ||||||
|         configuration.getDynamoDbTables().getRegistrationRecovery().getExpiration(), |         configuration.getDynamoDbTables().getRegistrationRecovery().getExpiration(), | ||||||
|  | @ -159,6 +156,7 @@ public class AssignUsernameCommand extends EnvironmentCommand<WhisperServerConfi | ||||||
|         configuration.getDynamoDbTables().getAccounts().getPhoneNumberTableName(), |         configuration.getDynamoDbTables().getAccounts().getPhoneNumberTableName(), | ||||||
|         configuration.getDynamoDbTables().getAccounts().getPhoneNumberIdentifierTableName(), |         configuration.getDynamoDbTables().getAccounts().getPhoneNumberIdentifierTableName(), | ||||||
|         configuration.getDynamoDbTables().getAccounts().getUsernamesTableName(), |         configuration.getDynamoDbTables().getAccounts().getUsernamesTableName(), | ||||||
|  |         configuration.getDynamoDbTables().getDeletedAccounts().getTableName(), | ||||||
|         configuration.getDynamoDbTables().getAccounts().getScanPageSize()); |         configuration.getDynamoDbTables().getAccounts().getScanPageSize()); | ||||||
|     PhoneNumberIdentifiers phoneNumberIdentifiers = new PhoneNumberIdentifiers(dynamoDbClient, |     PhoneNumberIdentifiers phoneNumberIdentifiers = new PhoneNumberIdentifiers(dynamoDbClient, | ||||||
|         configuration.getDynamoDbTables().getPhoneNumberIdentifiers().getTableName()); |         configuration.getDynamoDbTables().getPhoneNumberIdentifiers().getTableName()); | ||||||
|  | @ -206,7 +204,7 @@ public class AssignUsernameCommand extends EnvironmentCommand<WhisperServerConfi | ||||||
|     AccountLockManager accountLockManager = new AccountLockManager(dynamoDbClient, |     AccountLockManager accountLockManager = new AccountLockManager(dynamoDbClient, | ||||||
|         configuration.getDynamoDbTables().getDeletedAccountsLock().getTableName()); |         configuration.getDynamoDbTables().getDeletedAccountsLock().getTableName()); | ||||||
|     AccountsManager accountsManager = new AccountsManager(accounts, phoneNumberIdentifiers, cacheCluster, |     AccountsManager accountsManager = new AccountsManager(accounts, phoneNumberIdentifiers, cacheCluster, | ||||||
|         accountLockManager, deletedAccounts, keys, messagesManager, profilesManager, |         accountLockManager, keys, messagesManager, profilesManager, | ||||||
|             secureStorageClient, secureBackupClient, secureValueRecovery2Client, clientPresenceManager, |             secureStorageClient, secureBackupClient, secureValueRecovery2Client, clientPresenceManager, | ||||||
|         experimentEnrollmentManager, registrationRecoveryPasswordsManager, Clock.systemUTC()); |         experimentEnrollmentManager, registrationRecoveryPasswordsManager, Clock.systemUTC()); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -31,7 +31,6 @@ import org.whispersystems.textsecuregcm.securevaluerecovery.SecureValueRecovery2 | ||||||
| import org.whispersystems.textsecuregcm.storage.AccountLockManager; | import org.whispersystems.textsecuregcm.storage.AccountLockManager; | ||||||
| import org.whispersystems.textsecuregcm.storage.Accounts; | import org.whispersystems.textsecuregcm.storage.Accounts; | ||||||
| import org.whispersystems.textsecuregcm.storage.AccountsManager; | import org.whispersystems.textsecuregcm.storage.AccountsManager; | ||||||
| import org.whispersystems.textsecuregcm.storage.DeletedAccounts; |  | ||||||
| import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager; | import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager; | ||||||
| import org.whispersystems.textsecuregcm.storage.KeysManager; | import org.whispersystems.textsecuregcm.storage.KeysManager; | ||||||
| import org.whispersystems.textsecuregcm.storage.MessagesCache; | import org.whispersystems.textsecuregcm.storage.MessagesCache; | ||||||
|  | @ -117,8 +116,6 @@ record CommandDependencies( | ||||||
|     DynamoDbClient dynamoDbClient = DynamoDbFromConfig.client( |     DynamoDbClient dynamoDbClient = DynamoDbFromConfig.client( | ||||||
|         configuration.getDynamoDbClientConfiguration(), WhisperServerService.AWSSDK_CREDENTIALS_PROVIDER); |         configuration.getDynamoDbClientConfiguration(), WhisperServerService.AWSSDK_CREDENTIALS_PROVIDER); | ||||||
| 
 | 
 | ||||||
|     DeletedAccounts deletedAccounts = new DeletedAccounts(dynamoDbClient, |  | ||||||
|         configuration.getDynamoDbTables().getDeletedAccounts().getTableName()); |  | ||||||
|     RegistrationRecoveryPasswords registrationRecoveryPasswords = new RegistrationRecoveryPasswords( |     RegistrationRecoveryPasswords registrationRecoveryPasswords = new RegistrationRecoveryPasswords( | ||||||
|         configuration.getDynamoDbTables().getRegistrationRecovery().getTableName(), |         configuration.getDynamoDbTables().getRegistrationRecovery().getTableName(), | ||||||
|         configuration.getDynamoDbTables().getRegistrationRecovery().getExpiration(), |         configuration.getDynamoDbTables().getRegistrationRecovery().getExpiration(), | ||||||
|  | @ -136,6 +133,7 @@ record CommandDependencies( | ||||||
|         configuration.getDynamoDbTables().getAccounts().getPhoneNumberTableName(), |         configuration.getDynamoDbTables().getAccounts().getPhoneNumberTableName(), | ||||||
|         configuration.getDynamoDbTables().getAccounts().getPhoneNumberIdentifierTableName(), |         configuration.getDynamoDbTables().getAccounts().getPhoneNumberIdentifierTableName(), | ||||||
|         configuration.getDynamoDbTables().getAccounts().getUsernamesTableName(), |         configuration.getDynamoDbTables().getAccounts().getUsernamesTableName(), | ||||||
|  |         configuration.getDynamoDbTables().getDeletedAccounts().getTableName(), | ||||||
|         configuration.getDynamoDbTables().getAccounts().getScanPageSize()); |         configuration.getDynamoDbTables().getAccounts().getScanPageSize()); | ||||||
|     PhoneNumberIdentifiers phoneNumberIdentifiers = new PhoneNumberIdentifiers(dynamoDbClient, |     PhoneNumberIdentifiers phoneNumberIdentifiers = new PhoneNumberIdentifiers(dynamoDbClient, | ||||||
|         configuration.getDynamoDbTables().getPhoneNumberIdentifiers().getTableName()); |         configuration.getDynamoDbTables().getPhoneNumberIdentifiers().getTableName()); | ||||||
|  | @ -184,7 +182,7 @@ record CommandDependencies( | ||||||
|     AccountLockManager accountLockManager = new AccountLockManager(dynamoDbClient, |     AccountLockManager accountLockManager = new AccountLockManager(dynamoDbClient, | ||||||
|         configuration.getDynamoDbTables().getDeletedAccountsLock().getTableName()); |         configuration.getDynamoDbTables().getDeletedAccountsLock().getTableName()); | ||||||
|     AccountsManager accountsManager = new AccountsManager(accounts, phoneNumberIdentifiers, cacheCluster, |     AccountsManager accountsManager = new AccountsManager(accounts, phoneNumberIdentifiers, cacheCluster, | ||||||
|         accountLockManager, deletedAccounts, keys, messagesManager, profilesManager, |         accountLockManager, keys, messagesManager, profilesManager, | ||||||
|             secureStorageClient, secureBackupClient, secureValueRecovery2Client, |             secureStorageClient, secureBackupClient, secureValueRecovery2Client, | ||||||
|         clientPresenceManager, |         clientPresenceManager, | ||||||
|         experimentEnrollmentManager, registrationRecoveryPasswordsManager, clock); |         experimentEnrollmentManager, registrationRecoveryPasswordsManager, clock); | ||||||
|  |  | ||||||
|  | @ -113,7 +113,6 @@ import org.whispersystems.textsecuregcm.spam.ReportSpamTokenProvider; | ||||||
| import org.whispersystems.textsecuregcm.storage.Account; | import org.whispersystems.textsecuregcm.storage.Account; | ||||||
| import org.whispersystems.textsecuregcm.storage.AccountsManager; | import org.whispersystems.textsecuregcm.storage.AccountsManager; | ||||||
| import org.whispersystems.textsecuregcm.storage.ClientReleaseManager; | import org.whispersystems.textsecuregcm.storage.ClientReleaseManager; | ||||||
| import org.whispersystems.textsecuregcm.storage.DeletedAccounts; |  | ||||||
| import org.whispersystems.textsecuregcm.storage.Device; | import org.whispersystems.textsecuregcm.storage.Device; | ||||||
| import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager; | import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager; | ||||||
| import org.whispersystems.textsecuregcm.storage.MessagesManager; | import org.whispersystems.textsecuregcm.storage.MessagesManager; | ||||||
|  | @ -159,7 +158,6 @@ class MessageControllerTest { | ||||||
|   private static final MessageSender messageSender = mock(MessageSender.class); |   private static final MessageSender messageSender = mock(MessageSender.class); | ||||||
|   private static final ReceiptSender receiptSender = mock(ReceiptSender.class); |   private static final ReceiptSender receiptSender = mock(ReceiptSender.class); | ||||||
|   private static final AccountsManager accountsManager = mock(AccountsManager.class); |   private static final AccountsManager accountsManager = mock(AccountsManager.class); | ||||||
|   private static final DeletedAccounts deletedAccounts = mock(DeletedAccounts.class); |  | ||||||
|   private static final MessagesManager messagesManager = mock(MessagesManager.class); |   private static final MessagesManager messagesManager = mock(MessagesManager.class); | ||||||
|   private static final RateLimiters rateLimiters = mock(RateLimiters.class); |   private static final RateLimiters rateLimiters = mock(RateLimiters.class); | ||||||
|   private static final CardinalityEstimator cardinalityEstimator = mock(CardinalityEstimator.class); |   private static final CardinalityEstimator cardinalityEstimator = mock(CardinalityEstimator.class); | ||||||
|  | @ -179,7 +177,7 @@ class MessageControllerTest { | ||||||
|       .addProvider(MultiRecipientMessageProvider.class) |       .addProvider(MultiRecipientMessageProvider.class) | ||||||
|       .setTestContainerFactory(new GrizzlyWebTestContainerFactory()) |       .setTestContainerFactory(new GrizzlyWebTestContainerFactory()) | ||||||
|       .addResource( |       .addResource( | ||||||
|           new MessageController(rateLimiters, cardinalityEstimator, messageSender, receiptSender, accountsManager, deletedAccounts, |           new MessageController(rateLimiters, cardinalityEstimator, messageSender, receiptSender, accountsManager, | ||||||
|               messagesManager, pushNotificationManager, reportMessageManager, multiRecipientMessageExecutor, |               messagesManager, pushNotificationManager, reportMessageManager, multiRecipientMessageExecutor, | ||||||
|               messageDeliveryScheduler, ReportSpamTokenProvider.noop(), mock(ClientReleaseManager.class), dynamicConfigurationManager)) |               messageDeliveryScheduler, ReportSpamTokenProvider.noop(), mock(ClientReleaseManager.class), dynamicConfigurationManager)) | ||||||
|       .build(); |       .build(); | ||||||
|  | @ -245,7 +243,6 @@ class MessageControllerTest { | ||||||
|         messageSender, |         messageSender, | ||||||
|         receiptSender, |         receiptSender, | ||||||
|         accountsManager, |         accountsManager, | ||||||
|         deletedAccounts, |  | ||||||
|         messagesManager, |         messagesManager, | ||||||
|         rateLimiters, |         rateLimiters, | ||||||
|         rateLimiter, |         rateLimiter, | ||||||
|  | @ -681,7 +678,7 @@ class MessageControllerTest { | ||||||
|     when(account.getPhoneNumberIdentifier()).thenReturn(senderPni); |     when(account.getPhoneNumberIdentifier()).thenReturn(senderPni); | ||||||
| 
 | 
 | ||||||
|     when(accountsManager.getByE164(senderNumber)).thenReturn(Optional.of(account)); |     when(accountsManager.getByE164(senderNumber)).thenReturn(Optional.of(account)); | ||||||
|     when(deletedAccounts.findUuid(senderNumber)).thenReturn(Optional.of(senderAci)); |     when(accountsManager.findRecentlyDeletedAccountIdentifier(senderNumber)).thenReturn(Optional.of(senderAci)); | ||||||
|     when(accountsManager.getPhoneNumberIdentifier(senderNumber)).thenReturn(senderPni); |     when(accountsManager.getPhoneNumberIdentifier(senderNumber)).thenReturn(senderPni); | ||||||
| 
 | 
 | ||||||
|     Response response = |     Response response = | ||||||
|  | @ -696,7 +693,7 @@ class MessageControllerTest { | ||||||
| 
 | 
 | ||||||
|     verify(reportMessageManager).report(Optional.of(senderNumber), Optional.of(senderAci), Optional.of(senderPni), |     verify(reportMessageManager).report(Optional.of(senderNumber), Optional.of(senderAci), Optional.of(senderPni), | ||||||
|         messageGuid, AuthHelper.VALID_UUID, Optional.empty(), userAgent); |         messageGuid, AuthHelper.VALID_UUID, Optional.empty(), userAgent); | ||||||
|     verify(deletedAccounts, never()).findE164(any(UUID.class)); |     verify(accountsManager, never()).findRecentlyDeletedE164(any(UUID.class)); | ||||||
|     verify(accountsManager, never()).getPhoneNumberIdentifier(anyString()); |     verify(accountsManager, never()).getPhoneNumberIdentifier(anyString()); | ||||||
| 
 | 
 | ||||||
|     when(accountsManager.getByE164(senderNumber)).thenReturn(Optional.empty()); |     when(accountsManager.getByE164(senderNumber)).thenReturn(Optional.empty()); | ||||||
|  | @ -731,7 +728,7 @@ class MessageControllerTest { | ||||||
|     when(account.getPhoneNumberIdentifier()).thenReturn(senderPni); |     when(account.getPhoneNumberIdentifier()).thenReturn(senderPni); | ||||||
| 
 | 
 | ||||||
|     when(accountsManager.getByAccountIdentifier(senderAci)).thenReturn(Optional.of(account)); |     when(accountsManager.getByAccountIdentifier(senderAci)).thenReturn(Optional.of(account)); | ||||||
|     when(deletedAccounts.findE164(senderAci)).thenReturn(Optional.of(senderNumber)); |     when(accountsManager.findRecentlyDeletedE164(senderAci)).thenReturn(Optional.of(senderNumber)); | ||||||
|     when(accountsManager.getPhoneNumberIdentifier(senderNumber)).thenReturn(senderPni); |     when(accountsManager.getPhoneNumberIdentifier(senderNumber)).thenReturn(senderPni); | ||||||
| 
 | 
 | ||||||
|     Response response = |     Response response = | ||||||
|  | @ -746,7 +743,7 @@ class MessageControllerTest { | ||||||
| 
 | 
 | ||||||
|     verify(reportMessageManager).report(Optional.of(senderNumber), Optional.of(senderAci), Optional.of(senderPni), |     verify(reportMessageManager).report(Optional.of(senderNumber), Optional.of(senderAci), Optional.of(senderPni), | ||||||
|         messageGuid, AuthHelper.VALID_UUID, Optional.empty(), userAgent); |         messageGuid, AuthHelper.VALID_UUID, Optional.empty(), userAgent); | ||||||
|     verify(deletedAccounts, never()).findE164(any(UUID.class)); |     verify(accountsManager, never()).findRecentlyDeletedE164(any(UUID.class)); | ||||||
|     verify(accountsManager, never()).getPhoneNumberIdentifier(anyString()); |     verify(accountsManager, never()).getPhoneNumberIdentifier(anyString()); | ||||||
| 
 | 
 | ||||||
|     when(accountsManager.getByAccountIdentifier(senderAci)).thenReturn(Optional.empty()); |     when(accountsManager.getByAccountIdentifier(senderAci)).thenReturn(Optional.empty()); | ||||||
|  | @ -781,7 +778,7 @@ class MessageControllerTest { | ||||||
|     when(account.getPhoneNumberIdentifier()).thenReturn(senderPni); |     when(account.getPhoneNumberIdentifier()).thenReturn(senderPni); | ||||||
| 
 | 
 | ||||||
|     when(accountsManager.getByAccountIdentifier(senderAci)).thenReturn(Optional.of(account)); |     when(accountsManager.getByAccountIdentifier(senderAci)).thenReturn(Optional.of(account)); | ||||||
|     when(deletedAccounts.findE164(senderAci)).thenReturn(Optional.of(senderNumber)); |     when(accountsManager.findRecentlyDeletedE164(senderAci)).thenReturn(Optional.of(senderNumber)); | ||||||
|     when(accountsManager.getPhoneNumberIdentifier(senderNumber)).thenReturn(senderPni); |     when(accountsManager.getPhoneNumberIdentifier(senderNumber)).thenReturn(senderPni); | ||||||
| 
 | 
 | ||||||
|     Entity<SpamReport> entity = Entity.entity(new SpamReport(new byte[3]), "application/json"); |     Entity<SpamReport> entity = Entity.entity(new SpamReport(new byte[3]), "application/json"); | ||||||
|  | @ -800,7 +797,7 @@ class MessageControllerTest { | ||||||
|         eq(AuthHelper.VALID_UUID), |         eq(AuthHelper.VALID_UUID), | ||||||
|         argThat(maybeBytes -> maybeBytes.map(bytes -> Arrays.equals(bytes, new byte[3])).orElse(false)), |         argThat(maybeBytes -> maybeBytes.map(bytes -> Arrays.equals(bytes, new byte[3])).orElse(false)), | ||||||
|         any()); |         any()); | ||||||
|     verify(deletedAccounts, never()).findE164(any(UUID.class)); |     verify(accountsManager, never()).findRecentlyDeletedE164(any(UUID.class)); | ||||||
|     verify(accountsManager, never()).getPhoneNumberIdentifier(anyString()); |     verify(accountsManager, never()).getPhoneNumberIdentifier(anyString()); | ||||||
|     when(accountsManager.getByAccountIdentifier(senderAci)).thenReturn(Optional.empty()); |     when(accountsManager.getByAccountIdentifier(senderAci)).thenReturn(Optional.empty()); | ||||||
| 
 | 
 | ||||||
|  | @ -839,7 +836,7 @@ class MessageControllerTest { | ||||||
|     when(account.getPhoneNumberIdentifier()).thenReturn(senderPni); |     when(account.getPhoneNumberIdentifier()).thenReturn(senderPni); | ||||||
| 
 | 
 | ||||||
|     when(accountsManager.getByAccountIdentifier(senderAci)).thenReturn(Optional.of(account)); |     when(accountsManager.getByAccountIdentifier(senderAci)).thenReturn(Optional.of(account)); | ||||||
|     when(deletedAccounts.findE164(senderAci)).thenReturn(Optional.of(senderNumber)); |     when(accountsManager.findRecentlyDeletedE164(senderAci)).thenReturn(Optional.of(senderNumber)); | ||||||
|     when(accountsManager.getPhoneNumberIdentifier(senderNumber)).thenReturn(senderPni); |     when(accountsManager.getPhoneNumberIdentifier(senderNumber)).thenReturn(senderPni); | ||||||
| 
 | 
 | ||||||
|     Response response = |     Response response = | ||||||
|  |  | ||||||
|  | @ -58,7 +58,6 @@ class AccountsManagerChangeNumberIntegrationTest { | ||||||
|   static final RedisClusterExtension CACHE_CLUSTER_EXTENSION = RedisClusterExtension.builder().build(); |   static final RedisClusterExtension CACHE_CLUSTER_EXTENSION = RedisClusterExtension.builder().build(); | ||||||
| 
 | 
 | ||||||
|   private ClientPresenceManager clientPresenceManager; |   private ClientPresenceManager clientPresenceManager; | ||||||
|   private DeletedAccounts deletedAccounts; |  | ||||||
| 
 | 
 | ||||||
|   private AccountsManager accountsManager; |   private AccountsManager accountsManager; | ||||||
| 
 | 
 | ||||||
|  | @ -79,11 +78,9 @@ class AccountsManagerChangeNumberIntegrationTest { | ||||||
|           Tables.NUMBERS.tableName(), |           Tables.NUMBERS.tableName(), | ||||||
|           Tables.PNI_ASSIGNMENTS.tableName(), |           Tables.PNI_ASSIGNMENTS.tableName(), | ||||||
|           Tables.USERNAMES.tableName(), |           Tables.USERNAMES.tableName(), | ||||||
|  |           Tables.DELETED_ACCOUNTS.tableName(), | ||||||
|           SCAN_PAGE_SIZE); |           SCAN_PAGE_SIZE); | ||||||
| 
 | 
 | ||||||
|       deletedAccounts = new DeletedAccounts(DYNAMO_DB_EXTENSION.getDynamoDbClient(), |  | ||||||
|           Tables.DELETED_ACCOUNTS.tableName()); |  | ||||||
| 
 |  | ||||||
|       final AccountLockManager accountLockManager = new AccountLockManager(DYNAMO_DB_EXTENSION.getDynamoDbClient(), |       final AccountLockManager accountLockManager = new AccountLockManager(DYNAMO_DB_EXTENSION.getDynamoDbClient(), | ||||||
|           Tables.DELETED_ACCOUNTS_LOCK.tableName()); |           Tables.DELETED_ACCOUNTS_LOCK.tableName()); | ||||||
| 
 | 
 | ||||||
|  | @ -112,7 +109,6 @@ class AccountsManagerChangeNumberIntegrationTest { | ||||||
|           phoneNumberIdentifiers, |           phoneNumberIdentifiers, | ||||||
|           CACHE_CLUSTER_EXTENSION.getRedisCluster(), |           CACHE_CLUSTER_EXTENSION.getRedisCluster(), | ||||||
|           accountLockManager, |           accountLockManager, | ||||||
|           deletedAccounts, |  | ||||||
|           keysManager, |           keysManager, | ||||||
|           messagesManager, |           messagesManager, | ||||||
|           mock(ProfilesManager.class), |           mock(ProfilesManager.class), | ||||||
|  | @ -145,8 +141,8 @@ class AccountsManagerChangeNumberIntegrationTest { | ||||||
| 
 | 
 | ||||||
|     assertEquals(secondNumber, accountsManager.getByAccountIdentifier(originalUuid).map(Account::getNumber).orElseThrow()); |     assertEquals(secondNumber, accountsManager.getByAccountIdentifier(originalUuid).map(Account::getNumber).orElseThrow()); | ||||||
| 
 | 
 | ||||||
|     assertEquals(Optional.empty(), deletedAccounts.findUuid(originalNumber)); |     assertEquals(Optional.empty(), accountsManager.findRecentlyDeletedAccountIdentifier(originalNumber)); | ||||||
|     assertEquals(Optional.empty(), deletedAccounts.findUuid(secondNumber)); |     assertEquals(Optional.empty(), accountsManager.findRecentlyDeletedAccountIdentifier(secondNumber)); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
|  | @ -178,8 +174,8 @@ class AccountsManagerChangeNumberIntegrationTest { | ||||||
| 
 | 
 | ||||||
|     assertEquals(secondNumber, accountsManager.getByAccountIdentifier(originalUuid).map(Account::getNumber).orElseThrow()); |     assertEquals(secondNumber, accountsManager.getByAccountIdentifier(originalUuid).map(Account::getNumber).orElseThrow()); | ||||||
| 
 | 
 | ||||||
|     assertEquals(Optional.empty(), deletedAccounts.findUuid(originalNumber)); |     assertEquals(Optional.empty(), accountsManager.findRecentlyDeletedAccountIdentifier(originalNumber)); | ||||||
|     assertEquals(Optional.empty(), deletedAccounts.findUuid(secondNumber)); |     assertEquals(Optional.empty(), accountsManager.findRecentlyDeletedAccountIdentifier(secondNumber)); | ||||||
| 
 | 
 | ||||||
|     assertEquals(pniIdentityKey, updatedAccount.getIdentityKey(IdentityType.PNI)); |     assertEquals(pniIdentityKey, updatedAccount.getIdentityKey(IdentityType.PNI)); | ||||||
| 
 | 
 | ||||||
|  | @ -209,8 +205,8 @@ class AccountsManagerChangeNumberIntegrationTest { | ||||||
| 
 | 
 | ||||||
|     assertEquals(originalNumber, accountsManager.getByAccountIdentifier(originalUuid).map(Account::getNumber).orElseThrow()); |     assertEquals(originalNumber, accountsManager.getByAccountIdentifier(originalUuid).map(Account::getNumber).orElseThrow()); | ||||||
| 
 | 
 | ||||||
|     assertEquals(Optional.empty(), deletedAccounts.findUuid(originalNumber)); |     assertEquals(Optional.empty(), accountsManager.findRecentlyDeletedAccountIdentifier(originalNumber)); | ||||||
|     assertEquals(Optional.empty(), deletedAccounts.findUuid(secondNumber)); |     assertEquals(Optional.empty(), accountsManager.findRecentlyDeletedAccountIdentifier(secondNumber)); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
|  | @ -235,8 +231,8 @@ class AccountsManagerChangeNumberIntegrationTest { | ||||||
| 
 | 
 | ||||||
|     verify(clientPresenceManager).disconnectPresence(existingAccountUuid, Device.MASTER_ID); |     verify(clientPresenceManager).disconnectPresence(existingAccountUuid, Device.MASTER_ID); | ||||||
| 
 | 
 | ||||||
|     assertEquals(Optional.of(existingAccountUuid), deletedAccounts.findUuid(originalNumber)); |     assertEquals(Optional.of(existingAccountUuid), accountsManager.findRecentlyDeletedAccountIdentifier(originalNumber)); | ||||||
|     assertEquals(Optional.empty(), deletedAccounts.findUuid(secondNumber)); |     assertEquals(Optional.empty(), accountsManager.findRecentlyDeletedAccountIdentifier(secondNumber)); | ||||||
| 
 | 
 | ||||||
|     accountsManager.changeNumber(accountsManager.getByAccountIdentifier(originalUuid).orElseThrow(), originalNumber, null, null, null, null); |     accountsManager.changeNumber(accountsManager.getByAccountIdentifier(originalUuid).orElseThrow(), originalNumber, null, null, null, null); | ||||||
| 
 | 
 | ||||||
|  | @ -266,13 +262,13 @@ class AccountsManagerChangeNumberIntegrationTest { | ||||||
|     assertEquals(existingAccountUuid, reRegisteredAccount.getUuid()); |     assertEquals(existingAccountUuid, reRegisteredAccount.getUuid()); | ||||||
|     assertEquals(originalPni, reRegisteredAccount.getPhoneNumberIdentifier()); |     assertEquals(originalPni, reRegisteredAccount.getPhoneNumberIdentifier()); | ||||||
| 
 | 
 | ||||||
|     assertEquals(Optional.empty(), deletedAccounts.findUuid(originalNumber)); |     assertEquals(Optional.empty(), accountsManager.findRecentlyDeletedAccountIdentifier(originalNumber)); | ||||||
|     assertEquals(Optional.empty(), deletedAccounts.findUuid(secondNumber)); |     assertEquals(Optional.empty(), accountsManager.findRecentlyDeletedAccountIdentifier(secondNumber)); | ||||||
| 
 | 
 | ||||||
|     final Account changedNumberReRegisteredAccount = accountsManager.changeNumber(reRegisteredAccount, secondNumber, null, null, null, null); |     final Account changedNumberReRegisteredAccount = accountsManager.changeNumber(reRegisteredAccount, secondNumber, null, null, null, null); | ||||||
| 
 | 
 | ||||||
|     assertEquals(Optional.of(originalUuid), deletedAccounts.findUuid(originalNumber)); |     assertEquals(Optional.of(originalUuid), accountsManager.findRecentlyDeletedAccountIdentifier(originalNumber)); | ||||||
|     assertEquals(Optional.empty(), deletedAccounts.findUuid(secondNumber)); |     assertEquals(Optional.empty(), accountsManager.findRecentlyDeletedAccountIdentifier(secondNumber)); | ||||||
|     assertEquals(secondPni, changedNumberReRegisteredAccount.getPhoneNumberIdentifier()); |     assertEquals(secondPni, changedNumberReRegisteredAccount.getPhoneNumberIdentifier()); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -23,7 +23,6 @@ import java.io.IOException; | ||||||
| import java.time.Clock; | import java.time.Clock; | ||||||
| import java.time.Instant; | import java.time.Instant; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.Optional; |  | ||||||
| import java.util.UUID; | import java.util.UUID; | ||||||
| import java.util.concurrent.CompletableFuture; | import java.util.concurrent.CompletableFuture; | ||||||
| import java.util.concurrent.Executor; | import java.util.concurrent.Executor; | ||||||
|  | @ -63,7 +62,8 @@ class AccountsManagerConcurrentModificationIntegrationTest { | ||||||
|   static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension( |   static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension( | ||||||
|       Tables.ACCOUNTS, |       Tables.ACCOUNTS, | ||||||
|       Tables.NUMBERS, |       Tables.NUMBERS, | ||||||
|       Tables.PNI_ASSIGNMENTS |       Tables.PNI_ASSIGNMENTS, | ||||||
|  |       Tables.DELETED_ACCOUNTS | ||||||
|   ); |   ); | ||||||
| 
 | 
 | ||||||
|   private Accounts accounts; |   private Accounts accounts; | ||||||
|  | @ -88,6 +88,7 @@ class AccountsManagerConcurrentModificationIntegrationTest { | ||||||
|         Tables.NUMBERS.tableName(), |         Tables.NUMBERS.tableName(), | ||||||
|         Tables.PNI_ASSIGNMENTS.tableName(), |         Tables.PNI_ASSIGNMENTS.tableName(), | ||||||
|         Tables.USERNAMES.tableName(), |         Tables.USERNAMES.tableName(), | ||||||
|  |         Tables.DELETED_ACCOUNTS.tableName(), | ||||||
|         SCAN_PAGE_SIZE); |         SCAN_PAGE_SIZE); | ||||||
| 
 | 
 | ||||||
|     { |     { | ||||||
|  | @ -103,9 +104,6 @@ class AccountsManagerConcurrentModificationIntegrationTest { | ||||||
|         return null; |         return null; | ||||||
|       }).when(accountLockManager).withLock(any(), any()); |       }).when(accountLockManager).withLock(any(), any()); | ||||||
| 
 | 
 | ||||||
|       final DeletedAccounts deletedAccounts = mock(DeletedAccounts.class); |  | ||||||
|       when(deletedAccounts.findUuid(any())).thenReturn(Optional.empty()); |  | ||||||
| 
 |  | ||||||
|       final PhoneNumberIdentifiers phoneNumberIdentifiers = mock(PhoneNumberIdentifiers.class); |       final PhoneNumberIdentifiers phoneNumberIdentifiers = mock(PhoneNumberIdentifiers.class); | ||||||
|       when(phoneNumberIdentifiers.getPhoneNumberIdentifier(anyString())) |       when(phoneNumberIdentifiers.getPhoneNumberIdentifier(anyString())) | ||||||
|           .thenAnswer((Answer<UUID>) invocation -> UUID.randomUUID()); |           .thenAnswer((Answer<UUID>) invocation -> UUID.randomUUID()); | ||||||
|  | @ -115,7 +113,6 @@ class AccountsManagerConcurrentModificationIntegrationTest { | ||||||
|           phoneNumberIdentifiers, |           phoneNumberIdentifiers, | ||||||
|           RedisClusterHelper.builder().stringCommands(commands).build(), |           RedisClusterHelper.builder().stringCommands(commands).build(), | ||||||
|           accountLockManager, |           accountLockManager, | ||||||
|           deletedAccounts, |  | ||||||
|           mock(KeysManager.class), |           mock(KeysManager.class), | ||||||
|           mock(MessagesManager.class), |           mock(MessagesManager.class), | ||||||
|           mock(ProfilesManager.class), |           mock(ProfilesManager.class), | ||||||
|  |  | ||||||
|  | @ -92,7 +92,6 @@ class AccountsManagerTest { | ||||||
|   private static final byte[] ENCRYPTED_USERNAME_2 = Base64.getUrlDecoder().decode(BASE_64_URL_ENCRYPTED_USERNAME_2); |   private static final byte[] ENCRYPTED_USERNAME_2 = Base64.getUrlDecoder().decode(BASE_64_URL_ENCRYPTED_USERNAME_2); | ||||||
| 
 | 
 | ||||||
|   private Accounts accounts; |   private Accounts accounts; | ||||||
|   private DeletedAccounts deletedAccounts; |  | ||||||
|   private KeysManager keysManager; |   private KeysManager keysManager; | ||||||
|   private MessagesManager messagesManager; |   private MessagesManager messagesManager; | ||||||
|   private ProfilesManager profilesManager; |   private ProfilesManager profilesManager; | ||||||
|  | @ -125,7 +124,6 @@ class AccountsManagerTest { | ||||||
|   @BeforeEach |   @BeforeEach | ||||||
|   void setup() throws InterruptedException { |   void setup() throws InterruptedException { | ||||||
|     accounts = mock(Accounts.class); |     accounts = mock(Accounts.class); | ||||||
|     deletedAccounts = mock(DeletedAccounts.class); |  | ||||||
|     keysManager = mock(KeysManager.class); |     keysManager = mock(KeysManager.class); | ||||||
|     messagesManager = mock(MessagesManager.class); |     messagesManager = mock(MessagesManager.class); | ||||||
|     profilesManager = mock(ProfilesManager.class); |     profilesManager = mock(ProfilesManager.class); | ||||||
|  | @ -152,8 +150,6 @@ class AccountsManagerTest { | ||||||
|       return null; |       return null; | ||||||
|     }).when(accounts).changeNumber(any(), anyString(), any()); |     }).when(accounts).changeNumber(any(), anyString(), any()); | ||||||
| 
 | 
 | ||||||
|     when(deletedAccounts.findUuid(anyString())).thenReturn(Optional.empty()); |  | ||||||
| 
 |  | ||||||
|     final SecureStorageClient storageClient = mock(SecureStorageClient.class); |     final SecureStorageClient storageClient = mock(SecureStorageClient.class); | ||||||
|     when(storageClient.deleteStoredData(any())).thenReturn(CompletableFuture.completedFuture(null)); |     when(storageClient.deleteStoredData(any())).thenReturn(CompletableFuture.completedFuture(null)); | ||||||
| 
 | 
 | ||||||
|  | @ -202,7 +198,6 @@ class AccountsManagerTest { | ||||||
|             .stringAsyncCommands(asyncCommands) |             .stringAsyncCommands(asyncCommands) | ||||||
|             .build(), |             .build(), | ||||||
|         accountLockManager, |         accountLockManager, | ||||||
|         deletedAccounts, |  | ||||||
|         keysManager, |         keysManager, | ||||||
|         messagesManager, |         messagesManager, | ||||||
|         profilesManager, |         profilesManager, | ||||||
|  | @ -954,7 +949,7 @@ class AccountsManagerTest { | ||||||
|   void testCreateAccountRecentlyDeleted() throws InterruptedException { |   void testCreateAccountRecentlyDeleted() throws InterruptedException { | ||||||
|     final UUID recentlyDeletedUuid = UUID.randomUUID(); |     final UUID recentlyDeletedUuid = UUID.randomUUID(); | ||||||
| 
 | 
 | ||||||
|     when(deletedAccounts.findUuid(anyString())).thenReturn(Optional.of(recentlyDeletedUuid)); |     when(accounts.findRecentlyDeletedAccountIdentifier(anyString())).thenReturn(Optional.of(recentlyDeletedUuid)); | ||||||
|     when(accounts.create(any())).thenReturn(true); |     when(accounts.create(any())).thenReturn(true); | ||||||
| 
 | 
 | ||||||
|     final String e164 = "+18005550123"; |     final String e164 = "+18005550123"; | ||||||
|  | @ -1036,7 +1031,7 @@ class AccountsManagerTest { | ||||||
|     account = accountsManager.changeNumber(account, number, null, null, null, null); |     account = accountsManager.changeNumber(account, number, null, null, null, null); | ||||||
| 
 | 
 | ||||||
|     assertEquals(number, account.getNumber()); |     assertEquals(number, account.getNumber()); | ||||||
|     verify(deletedAccounts, never()).put(any(), any()); |     verify(accounts, never()).putRecentlyDeletedAccount(any(), any()); | ||||||
|     verify(keysManager, never()).delete(any()); |     verify(keysManager, never()).delete(any()); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -1052,7 +1047,6 @@ class AccountsManagerTest { | ||||||
|         "AccountsManager should not allow use of changeNumber with new PNI keys but without changing number"); |         "AccountsManager should not allow use of changeNumber with new PNI keys but without changing number"); | ||||||
| 
 | 
 | ||||||
|     verify(accounts, never()).update(any()); |     verify(accounts, never()).update(any()); | ||||||
|     verifyNoInteractions(deletedAccounts); |  | ||||||
|     verifyNoInteractions(keysManager); |     verifyNoInteractions(keysManager); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -1210,7 +1204,6 @@ class AccountsManagerTest { | ||||||
|         updatedAccount.getDevices().stream().collect(Collectors.toMap(Device::getId, d -> d.getPhoneNumberIdentityRegistrationId().getAsInt()))); |         updatedAccount.getDevices().stream().collect(Collectors.toMap(Device::getId, d -> d.getPhoneNumberIdentityRegistrationId().getAsInt()))); | ||||||
| 
 | 
 | ||||||
|     verify(accounts).update(any()); |     verify(accounts).update(any()); | ||||||
|     verifyNoInteractions(deletedAccounts); |  | ||||||
| 
 | 
 | ||||||
|     verify(keysManager).delete(oldPni); |     verify(keysManager).delete(oldPni); | ||||||
|   } |   } | ||||||
|  | @ -1264,7 +1257,6 @@ class AccountsManagerTest { | ||||||
|         updatedAccount.getDevices().stream().collect(Collectors.toMap(Device::getId, d -> d.getPhoneNumberIdentityRegistrationId().getAsInt()))); |         updatedAccount.getDevices().stream().collect(Collectors.toMap(Device::getId, d -> d.getPhoneNumberIdentityRegistrationId().getAsInt()))); | ||||||
| 
 | 
 | ||||||
|     verify(accounts).update(any()); |     verify(accounts).update(any()); | ||||||
|     verifyNoInteractions(deletedAccounts); |  | ||||||
| 
 | 
 | ||||||
|     verify(keysManager).delete(oldPni); |     verify(keysManager).delete(oldPni); | ||||||
|     verify(keysManager).storeEcSignedPreKeys(oldPni, newSignedKeys); |     verify(keysManager).storeEcSignedPreKeys(oldPni, newSignedKeys); | ||||||
|  | @ -1297,7 +1289,6 @@ class AccountsManagerTest { | ||||||
|         () -> accountsManager.updatePniKeys(account, pniIdentityKey, newSignedKeys, null, newRegistrationIds)); |         () -> accountsManager.updatePniKeys(account, pniIdentityKey, newSignedKeys, null, newRegistrationIds)); | ||||||
| 
 | 
 | ||||||
|     verifyNoInteractions(accounts); |     verifyNoInteractions(accounts); | ||||||
|     verifyNoInteractions(deletedAccounts); |  | ||||||
|     verifyNoInteractions(keysManager); |     verifyNoInteractions(keysManager); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -1327,7 +1318,6 @@ class AccountsManagerTest { | ||||||
|         () -> accountsManager.updatePniKeys(account, pniIdentityKey, newSignedKeys, newSignedPqKeys, newRegistrationIds)); |         () -> accountsManager.updatePniKeys(account, pniIdentityKey, newSignedKeys, newSignedPqKeys, newRegistrationIds)); | ||||||
| 
 | 
 | ||||||
|     verifyNoInteractions(accounts); |     verifyNoInteractions(accounts); | ||||||
|     verifyNoInteractions(deletedAccounts); |  | ||||||
|     verifyNoInteractions(keysManager); |     verifyNoInteractions(keysManager); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -28,7 +28,6 @@ import java.util.Base64; | ||||||
| import java.util.HashMap; | import java.util.HashMap; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.Optional; |  | ||||||
| import java.util.UUID; | import java.util.UUID; | ||||||
| import org.junit.jupiter.api.BeforeEach; | import org.junit.jupiter.api.BeforeEach; | ||||||
| import org.junit.jupiter.api.Test; | import org.junit.jupiter.api.Test; | ||||||
|  | @ -65,6 +64,7 @@ class AccountsManagerUsernameIntegrationTest { | ||||||
|       Tables.ACCOUNTS, |       Tables.ACCOUNTS, | ||||||
|       Tables.NUMBERS, |       Tables.NUMBERS, | ||||||
|       Tables.USERNAMES, |       Tables.USERNAMES, | ||||||
|  |       Tables.DELETED_ACCOUNTS, | ||||||
|       Tables.PNI, |       Tables.PNI, | ||||||
|       Tables.PNI_ASSIGNMENTS); |       Tables.PNI_ASSIGNMENTS); | ||||||
| 
 | 
 | ||||||
|  | @ -94,6 +94,7 @@ class AccountsManagerUsernameIntegrationTest { | ||||||
|         Tables.NUMBERS.tableName(), |         Tables.NUMBERS.tableName(), | ||||||
|         Tables.PNI_ASSIGNMENTS.tableName(), |         Tables.PNI_ASSIGNMENTS.tableName(), | ||||||
|         Tables.USERNAMES.tableName(), |         Tables.USERNAMES.tableName(), | ||||||
|  |         Tables.DELETED_ACCOUNTS.tableName(), | ||||||
|         SCAN_PAGE_SIZE)); |         SCAN_PAGE_SIZE)); | ||||||
| 
 | 
 | ||||||
|     final AccountLockManager accountLockManager = mock(AccountLockManager.class); |     final AccountLockManager accountLockManager = mock(AccountLockManager.class); | ||||||
|  | @ -105,9 +106,6 @@ class AccountsManagerUsernameIntegrationTest { | ||||||
|       return null; |       return null; | ||||||
|     }).when(accountLockManager).withLock(any(), any()); |     }).when(accountLockManager).withLock(any(), any()); | ||||||
| 
 | 
 | ||||||
|     final DeletedAccounts deletedAccounts = mock(DeletedAccounts.class); |  | ||||||
|     when(deletedAccounts.findUuid(any())).thenReturn(Optional.empty()); |  | ||||||
| 
 |  | ||||||
|     final PhoneNumberIdentifiers phoneNumberIdentifiers = |     final PhoneNumberIdentifiers phoneNumberIdentifiers = | ||||||
|         new PhoneNumberIdentifiers(DYNAMO_DB_EXTENSION.getDynamoDbClient(), Tables.PNI.tableName()); |         new PhoneNumberIdentifiers(DYNAMO_DB_EXTENSION.getDynamoDbClient(), Tables.PNI.tableName()); | ||||||
| 
 | 
 | ||||||
|  | @ -119,7 +117,6 @@ class AccountsManagerUsernameIntegrationTest { | ||||||
|         phoneNumberIdentifiers, |         phoneNumberIdentifiers, | ||||||
|         CACHE_CLUSTER_EXTENSION.getRedisCluster(), |         CACHE_CLUSTER_EXTENSION.getRedisCluster(), | ||||||
|         accountLockManager, |         accountLockManager, | ||||||
|         deletedAccounts, |  | ||||||
|         mock(KeysManager.class), |         mock(KeysManager.class), | ||||||
|         mock(MessagesManager.class), |         mock(MessagesManager.class), | ||||||
|         mock(ProfilesManager.class), |         mock(ProfilesManager.class), | ||||||
|  |  | ||||||
|  | @ -98,7 +98,8 @@ class AccountsTest { | ||||||
|       Tables.ACCOUNTS, |       Tables.ACCOUNTS, | ||||||
|       Tables.NUMBERS, |       Tables.NUMBERS, | ||||||
|       Tables.PNI_ASSIGNMENTS, |       Tables.PNI_ASSIGNMENTS, | ||||||
|       Tables.USERNAMES); |       Tables.USERNAMES, | ||||||
|  |       Tables.DELETED_ACCOUNTS); | ||||||
| 
 | 
 | ||||||
|   private final TestClock clock = TestClock.pinned(Instant.EPOCH); |   private final TestClock clock = TestClock.pinned(Instant.EPOCH); | ||||||
|   private DynamicConfigurationManager<DynamicConfiguration> mockDynamicConfigManager; |   private DynamicConfigurationManager<DynamicConfiguration> mockDynamicConfigManager; | ||||||
|  | @ -121,6 +122,7 @@ class AccountsTest { | ||||||
|         Tables.NUMBERS.tableName(), |         Tables.NUMBERS.tableName(), | ||||||
|         Tables.PNI_ASSIGNMENTS.tableName(), |         Tables.PNI_ASSIGNMENTS.tableName(), | ||||||
|         Tables.USERNAMES.tableName(), |         Tables.USERNAMES.tableName(), | ||||||
|  |         Tables.DELETED_ACCOUNTS.tableName(), | ||||||
|         SCAN_PAGE_SIZE); |         SCAN_PAGE_SIZE); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -166,7 +168,6 @@ class AccountsTest { | ||||||
|         mock(PhoneNumberIdentifiers.class), |         mock(PhoneNumberIdentifiers.class), | ||||||
|         mock(FaultTolerantRedisCluster.class), |         mock(FaultTolerantRedisCluster.class), | ||||||
|         mock(AccountLockManager.class), |         mock(AccountLockManager.class), | ||||||
|         mock(DeletedAccounts.class), |  | ||||||
|         mock(KeysManager.class), |         mock(KeysManager.class), | ||||||
|         mock(MessagesManager.class), |         mock(MessagesManager.class), | ||||||
|         mock(ProfilesManager.class), |         mock(ProfilesManager.class), | ||||||
|  | @ -442,7 +443,8 @@ class AccountsTest { | ||||||
|     final DynamoDbAsyncClient dynamoDbAsyncClient = mock(DynamoDbAsyncClient.class); |     final DynamoDbAsyncClient dynamoDbAsyncClient = mock(DynamoDbAsyncClient.class); | ||||||
|     accounts = new Accounts(mock(DynamoDbClient.class), |     accounts = new Accounts(mock(DynamoDbClient.class), | ||||||
|         dynamoDbAsyncClient, Tables.ACCOUNTS.tableName(), |         dynamoDbAsyncClient, Tables.ACCOUNTS.tableName(), | ||||||
|         Tables.NUMBERS.tableName(), Tables.PNI_ASSIGNMENTS.tableName(), Tables.USERNAMES.tableName(), SCAN_PAGE_SIZE); |         Tables.NUMBERS.tableName(), Tables.PNI_ASSIGNMENTS.tableName(), Tables.USERNAMES.tableName(), | ||||||
|  |         Tables.DELETED_ACCOUNTS.tableName(), SCAN_PAGE_SIZE); | ||||||
| 
 | 
 | ||||||
|     Exception e = TransactionConflictException.builder().build(); |     Exception e = TransactionConflictException.builder().build(); | ||||||
|     e = wrapException ? new CompletionException(e) : e; |     e = wrapException ? new CompletionException(e) : e; | ||||||
|  | @ -990,6 +992,59 @@ class AccountsTest { | ||||||
|     assertThat(account.getUsernameHash()).isEmpty(); |     assertThat(account.getUsernameHash()).isEmpty(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   @Test | ||||||
|  |   void testPutFindRecentlyDeletedAccount() { | ||||||
|  |     final UUID uuid = UUID.randomUUID(); | ||||||
|  |     final String e164 = "+18005551234"; | ||||||
|  | 
 | ||||||
|  |     assertEquals(Optional.empty(), accounts.findRecentlyDeletedAccountIdentifier(e164)); | ||||||
|  | 
 | ||||||
|  |     accounts.putRecentlyDeletedAccount(uuid, e164); | ||||||
|  | 
 | ||||||
|  |     assertEquals(Optional.of(uuid), accounts.findRecentlyDeletedAccountIdentifier(e164)); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @Test | ||||||
|  |   void testRemoveRecentlyDeletedAccount() { | ||||||
|  |     final UUID uuid = UUID.randomUUID(); | ||||||
|  |     final String e164 = "+18005551234"; | ||||||
|  | 
 | ||||||
|  |     assertEquals(Optional.empty(), accounts.findRecentlyDeletedAccountIdentifier(e164)); | ||||||
|  | 
 | ||||||
|  |     accounts.putRecentlyDeletedAccount(uuid, e164); | ||||||
|  | 
 | ||||||
|  |     assertEquals(Optional.of(uuid), accounts.findRecentlyDeletedAccountIdentifier(e164)); | ||||||
|  | 
 | ||||||
|  |     accounts.removeRecentlyDeletedAccount(e164); | ||||||
|  | 
 | ||||||
|  |     assertEquals(Optional.empty(), accounts.findRecentlyDeletedAccountIdentifier(e164)); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @Test | ||||||
|  |   void testFindRecentlyDeletedE164() { | ||||||
|  |     assertEquals(Optional.empty(), accounts.findRecentlyDeletedE164(UUID.randomUUID())); | ||||||
|  | 
 | ||||||
|  |     final UUID uuid = UUID.randomUUID(); | ||||||
|  |     final String e164 = "+18005551234"; | ||||||
|  | 
 | ||||||
|  |     accounts.putRecentlyDeletedAccount(uuid, e164); | ||||||
|  | 
 | ||||||
|  |     assertEquals(Optional.of(e164), accounts.findRecentlyDeletedE164(uuid)); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @Test | ||||||
|  |   void testFindRecentlyDeletedUUID() { | ||||||
|  |     final String e164 = "+18005551234"; | ||||||
|  | 
 | ||||||
|  |     assertEquals(Optional.empty(), accounts.findRecentlyDeletedAccountIdentifier(e164)); | ||||||
|  | 
 | ||||||
|  |     final UUID uuid = UUID.randomUUID(); | ||||||
|  | 
 | ||||||
|  |     accounts.putRecentlyDeletedAccount(uuid, e164); | ||||||
|  | 
 | ||||||
|  |     assertEquals(Optional.of(uuid), accounts.findRecentlyDeletedAccountIdentifier(e164)); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   @Test |   @Test | ||||||
|   public void testIgnoredFieldsNotAddedToDataAttribute() throws Exception { |   public void testIgnoredFieldsNotAddedToDataAttribute() throws Exception { | ||||||
|     final Account account = generateAccount("+18005551234", UUID.randomUUID(), UUID.randomUUID()); |     final Account account = generateAccount("+18005551234", UUID.randomUUID(), UUID.randomUUID()); | ||||||
|  |  | ||||||
|  | @ -1,80 +0,0 @@ | ||||||
| /* |  | ||||||
|  * Copyright 2013-2021 Signal Messenger, LLC |  | ||||||
|  * SPDX-License-Identifier: AGPL-3.0-only |  | ||||||
|  */ |  | ||||||
| package org.whispersystems.textsecuregcm.storage; |  | ||||||
| 
 |  | ||||||
| import static org.junit.jupiter.api.Assertions.assertEquals; |  | ||||||
| 
 |  | ||||||
| import java.util.Optional; |  | ||||||
| import java.util.UUID; |  | ||||||
| import org.junit.jupiter.api.BeforeEach; |  | ||||||
| import org.junit.jupiter.api.Test; |  | ||||||
| import org.junit.jupiter.api.extension.RegisterExtension; |  | ||||||
| import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables; |  | ||||||
| 
 |  | ||||||
| class DeletedAccountsTest { |  | ||||||
| 
 |  | ||||||
|   @RegisterExtension |  | ||||||
|   static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(Tables.DELETED_ACCOUNTS); |  | ||||||
| 
 |  | ||||||
|   private DeletedAccounts deletedAccounts; |  | ||||||
| 
 |  | ||||||
|   @BeforeEach |  | ||||||
|   void setUp() { |  | ||||||
|     deletedAccounts = new DeletedAccounts(DYNAMO_DB_EXTENSION.getDynamoDbClient(), Tables.DELETED_ACCOUNTS.tableName()); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Test |  | ||||||
|   void testPutFind() { |  | ||||||
|     final UUID uuid = UUID.randomUUID(); |  | ||||||
|     final String e164 = "+18005551234"; |  | ||||||
| 
 |  | ||||||
|     assertEquals(Optional.empty(), deletedAccounts.findUuid(e164)); |  | ||||||
| 
 |  | ||||||
|     deletedAccounts.put(uuid, e164); |  | ||||||
| 
 |  | ||||||
|     assertEquals(Optional.of(uuid), deletedAccounts.findUuid(e164)); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Test |  | ||||||
|   void testRemove() { |  | ||||||
|     final UUID uuid = UUID.randomUUID(); |  | ||||||
|     final String e164 = "+18005551234"; |  | ||||||
| 
 |  | ||||||
|     assertEquals(Optional.empty(), deletedAccounts.findUuid(e164)); |  | ||||||
| 
 |  | ||||||
|     deletedAccounts.put(uuid, e164); |  | ||||||
| 
 |  | ||||||
|     assertEquals(Optional.of(uuid), deletedAccounts.findUuid(e164)); |  | ||||||
| 
 |  | ||||||
|     deletedAccounts.remove(e164); |  | ||||||
| 
 |  | ||||||
|     assertEquals(Optional.empty(), deletedAccounts.findUuid(e164)); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Test |  | ||||||
|   void testFindE164() { |  | ||||||
|     assertEquals(Optional.empty(), deletedAccounts.findE164(UUID.randomUUID())); |  | ||||||
| 
 |  | ||||||
|     final UUID uuid = UUID.randomUUID(); |  | ||||||
|     final String e164 = "+18005551234"; |  | ||||||
| 
 |  | ||||||
|     deletedAccounts.put(uuid, e164); |  | ||||||
| 
 |  | ||||||
|     assertEquals(Optional.of(e164), deletedAccounts.findE164(uuid)); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Test |  | ||||||
|   void testFindUUID() { |  | ||||||
|     final String e164 = "+18005551234"; |  | ||||||
| 
 |  | ||||||
|     assertEquals(Optional.empty(), deletedAccounts.findUuid(e164)); |  | ||||||
| 
 |  | ||||||
|     final UUID uuid = UUID.randomUUID(); |  | ||||||
| 
 |  | ||||||
|     deletedAccounts.put(uuid, e164); |  | ||||||
| 
 |  | ||||||
|     assertEquals(Optional.of(uuid), deletedAccounts.findUuid(e164)); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  | @ -63,21 +63,21 @@ public final class DynamoDbExtensionSchema { | ||||||
|         List.of()), |         List.of()), | ||||||
| 
 | 
 | ||||||
|     DELETED_ACCOUNTS("deleted_accounts_test", |     DELETED_ACCOUNTS("deleted_accounts_test", | ||||||
|         DeletedAccounts.KEY_ACCOUNT_E164, |         Accounts.DELETED_ACCOUNTS_KEY_ACCOUNT_E164, | ||||||
|         null, |         null, | ||||||
|         List.of( |         List.of( | ||||||
|             AttributeDefinition.builder() |             AttributeDefinition.builder() | ||||||
|                 .attributeName(DeletedAccounts.KEY_ACCOUNT_E164) |                 .attributeName(Accounts.DELETED_ACCOUNTS_KEY_ACCOUNT_E164) | ||||||
|                 .attributeType(ScalarAttributeType.S).build(), |                 .attributeType(ScalarAttributeType.S).build(), | ||||||
|             AttributeDefinition.builder() |             AttributeDefinition.builder() | ||||||
|                 .attributeName(DeletedAccounts.ATTR_ACCOUNT_UUID) |                 .attributeName(Accounts.DELETED_ACCOUNTS_ATTR_ACCOUNT_UUID) | ||||||
|                 .attributeType(ScalarAttributeType.B) |                 .attributeType(ScalarAttributeType.B) | ||||||
|                 .build()), |                 .build()), | ||||||
|         List.of( |         List.of( | ||||||
|             GlobalSecondaryIndex.builder() |             GlobalSecondaryIndex.builder() | ||||||
|                 .indexName(DeletedAccounts.UUID_TO_E164_INDEX_NAME) |                 .indexName(Accounts.DELETED_ACCOUNTS_UUID_TO_E164_INDEX_NAME) | ||||||
|                 .keySchema( |                 .keySchema( | ||||||
|                     KeySchemaElement.builder().attributeName(DeletedAccounts.ATTR_ACCOUNT_UUID).keyType(KeyType.HASH).build() |                     KeySchemaElement.builder().attributeName(Accounts.DELETED_ACCOUNTS_ATTR_ACCOUNT_UUID).keyType(KeyType.HASH).build() | ||||||
|                 ) |                 ) | ||||||
|                 .projection(Projection.builder().projectionType(ProjectionType.KEYS_ONLY).build()) |                 .projection(Projection.builder().projectionType(ProjectionType.KEYS_ONLY).build()) | ||||||
|                 .provisionedThroughput(ProvisionedThroughput.builder().readCapacityUnits(10L).writeCapacityUnits(10L).build()) |                 .provisionedThroughput(ProvisionedThroughput.builder().readCapacityUnits(10L).writeCapacityUnits(10L).build()) | ||||||
|  | @ -86,10 +86,10 @@ public final class DynamoDbExtensionSchema { | ||||||
|     ), |     ), | ||||||
|    |    | ||||||
|     DELETED_ACCOUNTS_LOCK("deleted_accounts_lock_test", |     DELETED_ACCOUNTS_LOCK("deleted_accounts_lock_test", | ||||||
|         DeletedAccounts.KEY_ACCOUNT_E164, |         AccountLockManager.KEY_ACCOUNT_E164, | ||||||
|         null, |         null, | ||||||
|         List.of(AttributeDefinition.builder() |         List.of(AttributeDefinition.builder() | ||||||
|             .attributeName(DeletedAccounts.KEY_ACCOUNT_E164) |             .attributeName(AccountLockManager.KEY_ACCOUNT_E164) | ||||||
|             .attributeType(ScalarAttributeType.S).build()), |             .attributeType(ScalarAttributeType.S).build()), | ||||||
|         List.of(), List.of()), |         List.of(), List.of()), | ||||||
|      |      | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Jon Chambers
						Jon Chambers