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