mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-21 18:58:04 +01:00
Remove signed pre-keys transactionally when removing devices
This commit is contained in:
@@ -97,7 +97,7 @@ class DevicesGrpcServiceTest extends SimpleBaseGrpcTest<DevicesGrpcService, Devi
|
||||
return CompletableFuture.completedFuture(account);
|
||||
});
|
||||
|
||||
when(keysManager.delete(any(), anyByte())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(keysManager.deleteSingleUsePreKeys(any(), anyByte())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(messagesManager.clear(any(), anyByte())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
return new DevicesGrpcService(accountsManager, keysManager, messagesManager);
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.whispersystems.textsecuregcm.storage;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
@@ -27,6 +28,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junitpioneer.jupiter.cartesian.ArgumentSets;
|
||||
import org.junitpioneer.jupiter.cartesian.CartesianTest;
|
||||
@@ -34,6 +36,7 @@ import org.signal.libsignal.protocol.IdentityKey;
|
||||
import org.signal.libsignal.protocol.ecc.Curve;
|
||||
import org.signal.libsignal.protocol.ecc.ECKeyPair;
|
||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicECPreKeyMigrationConfiguration;
|
||||
import org.whispersystems.textsecuregcm.entities.AccountAttributes;
|
||||
import org.whispersystems.textsecuregcm.entities.ApnRegistrationId;
|
||||
import org.whispersystems.textsecuregcm.entities.ECSignedPreKey;
|
||||
@@ -47,7 +50,7 @@ import org.whispersystems.textsecuregcm.securestorage.SecureStorageClient;
|
||||
import org.whispersystems.textsecuregcm.securevaluerecovery.SecureValueRecovery2Client;
|
||||
import org.whispersystems.textsecuregcm.tests.util.KeysHelper;
|
||||
|
||||
public class AccountCreationIntegrationTest {
|
||||
public class AccountCreationDeletionIntegrationTest {
|
||||
|
||||
@RegisterExtension
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(
|
||||
@@ -81,8 +84,10 @@ public class AccountCreationIntegrationTest {
|
||||
@SuppressWarnings("unchecked") final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager =
|
||||
mock(DynamicConfigurationManager.class);
|
||||
|
||||
DynamicConfiguration dynamicConfiguration = new DynamicConfiguration();
|
||||
final DynamicConfiguration dynamicConfiguration = mock(DynamicConfiguration.class);
|
||||
when(dynamicConfigurationManager.getConfiguration()).thenReturn(dynamicConfiguration);
|
||||
when(dynamicConfiguration.getEcPreKeyMigrationConfiguration())
|
||||
.thenReturn(new DynamicECPreKeyMigrationConfiguration(true, true));
|
||||
|
||||
keysManager = new KeysManager(
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient(),
|
||||
@@ -248,6 +253,25 @@ public class AccountCreationIntegrationTest {
|
||||
pniSignedPreKey,
|
||||
aciPqLastResortPreKey,
|
||||
pniPqLastResortPreKey);
|
||||
|
||||
assertEquals(Optional.of(aciSignedPreKey), keysManager.getEcSignedPreKey(account.getUuid(), Device.PRIMARY_ID).join());
|
||||
assertEquals(Optional.of(pniSignedPreKey), keysManager.getEcSignedPreKey(account.getPhoneNumberIdentifier(), Device.PRIMARY_ID).join());
|
||||
assertEquals(Optional.of(aciPqLastResortPreKey), keysManager.getLastResort(account.getUuid(), Device.PRIMARY_ID).join());
|
||||
assertEquals(Optional.of(pniPqLastResortPreKey), keysManager.getLastResort(account.getPhoneNumberIdentifier(), Device.PRIMARY_ID).join());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static ArgumentSets createAccount() {
|
||||
return ArgumentSets
|
||||
// deliveryChannels
|
||||
.argumentsForFirstParameter(
|
||||
new DeliveryChannels(true, null, null, null),
|
||||
new DeliveryChannels(false, "apns-token", null, null),
|
||||
new DeliveryChannels(false, "apns-token", "apns-voip-token", null),
|
||||
new DeliveryChannels(false, null, null, "fcm-token"))
|
||||
|
||||
// discoverableByPhoneNumber
|
||||
.argumentsForNextParameter(true, false);
|
||||
}
|
||||
|
||||
@CartesianTest
|
||||
@@ -375,18 +399,77 @@ public class AccountCreationIntegrationTest {
|
||||
assertEquals(existingAccountUuid, reregisteredAccount.getUuid());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static ArgumentSets createAccount() {
|
||||
return ArgumentSets
|
||||
// deliveryChannels
|
||||
.argumentsForFirstParameter(
|
||||
new DeliveryChannels(true, null, null, null),
|
||||
new DeliveryChannels(false, "apns-token", null, null),
|
||||
new DeliveryChannels(false, "apns-token", "apns-voip-token", null),
|
||||
new DeliveryChannels(false, null, null, "fcm-token"))
|
||||
@Test
|
||||
void deleteAccount() throws InterruptedException {
|
||||
final String number = PhoneNumberUtil.getInstance().format(
|
||||
PhoneNumberUtil.getInstance().getExampleNumber("US"),
|
||||
PhoneNumberUtil.PhoneNumberFormat.E164);
|
||||
|
||||
// discoverableByPhoneNumber
|
||||
.argumentsForNextParameter(true, false);
|
||||
final String password = RandomStringUtils.randomAlphanumeric(16);
|
||||
final String signalAgent = RandomStringUtils.randomAlphabetic(3);
|
||||
final int registrationId = ThreadLocalRandom.current().nextInt(Device.MAX_REGISTRATION_ID);
|
||||
final int pniRegistrationId = ThreadLocalRandom.current().nextInt(Device.MAX_REGISTRATION_ID);
|
||||
final byte[] deviceName = RandomStringUtils.randomAlphabetic(16).getBytes(StandardCharsets.UTF_8);
|
||||
final String registrationLockSecret = RandomStringUtils.randomAlphanumeric(16);
|
||||
|
||||
final Device.DeviceCapabilities deviceCapabilities = new Device.DeviceCapabilities(
|
||||
ThreadLocalRandom.current().nextBoolean(),
|
||||
ThreadLocalRandom.current().nextBoolean(),
|
||||
ThreadLocalRandom.current().nextBoolean(),
|
||||
ThreadLocalRandom.current().nextBoolean());
|
||||
|
||||
final AccountAttributes accountAttributes = new AccountAttributes(true,
|
||||
registrationId,
|
||||
pniRegistrationId,
|
||||
deviceName,
|
||||
registrationLockSecret,
|
||||
true,
|
||||
deviceCapabilities);
|
||||
|
||||
final List<AccountBadge> badges = new ArrayList<>(List.of(new AccountBadge(
|
||||
RandomStringUtils.randomAlphabetic(8),
|
||||
CLOCK.instant().plus(Duration.ofDays(7)),
|
||||
true)));
|
||||
|
||||
final ECKeyPair aciKeyPair = Curve.generateKeyPair();
|
||||
final ECKeyPair pniKeyPair = Curve.generateKeyPair();
|
||||
|
||||
final ECSignedPreKey aciSignedPreKey = KeysHelper.signedECPreKey(1, aciKeyPair);
|
||||
final ECSignedPreKey pniSignedPreKey = KeysHelper.signedECPreKey(2, pniKeyPair);
|
||||
final KEMSignedPreKey aciPqLastResortPreKey = KeysHelper.signedKEMPreKey(3, aciKeyPair);
|
||||
final KEMSignedPreKey pniPqLastResortPreKey = KeysHelper.signedKEMPreKey(4, pniKeyPair);
|
||||
|
||||
final Account account = accountsManager.create(number,
|
||||
accountAttributes,
|
||||
badges,
|
||||
new IdentityKey(aciKeyPair.getPublicKey()),
|
||||
new IdentityKey(pniKeyPair.getPublicKey()),
|
||||
new DeviceSpec(
|
||||
deviceName,
|
||||
password,
|
||||
signalAgent,
|
||||
deviceCapabilities,
|
||||
registrationId,
|
||||
pniRegistrationId,
|
||||
true,
|
||||
Optional.empty(),
|
||||
Optional.empty(),
|
||||
aciSignedPreKey,
|
||||
pniSignedPreKey,
|
||||
aciPqLastResortPreKey,
|
||||
pniPqLastResortPreKey));
|
||||
|
||||
final UUID aci = account.getIdentifier(IdentityType.ACI);
|
||||
|
||||
assertTrue(accountsManager.getByAccountIdentifier(aci).isPresent());
|
||||
|
||||
accountsManager.delete(account, AccountsManager.DeletionReason.ADMIN_DELETED).join();
|
||||
|
||||
assertFalse(accountsManager.getByAccountIdentifier(aci).isPresent());
|
||||
assertFalse(keysManager.getEcSignedPreKey(account.getUuid(), Device.PRIMARY_ID).join().isPresent());
|
||||
assertFalse(keysManager.getEcSignedPreKey(account.getPhoneNumberIdentifier(), Device.PRIMARY_ID).join().isPresent());
|
||||
assertFalse(keysManager.getLastResort(account.getUuid(), Device.PRIMARY_ID).join().isPresent());
|
||||
assertFalse(keysManager.getLastResort(account.getPhoneNumberIdentifier(), Device.PRIMARY_ID).join().isPresent());
|
||||
}
|
||||
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
@@ -14,7 +14,6 @@ import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyByte;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
@@ -159,7 +158,7 @@ class AccountsManagerTest {
|
||||
|
||||
when(accounts.updateAsync(any())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(accounts.updateTransactionallyAsync(any(), any())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(accounts.delete(any())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(accounts.delete(any(), any())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
doAnswer((Answer<Void>) invocation -> {
|
||||
final Account account = invocation.getArgument(0, Account.class);
|
||||
@@ -207,9 +206,7 @@ class AccountsManagerTest {
|
||||
|
||||
when(accountLockManager.withLockAsync(any(), any(), any())).thenAnswer(invocation -> {
|
||||
final Supplier<CompletableFuture<?>> taskSupplier = invocation.getArgument(1);
|
||||
taskSupplier.get().join();
|
||||
|
||||
return CompletableFuture.completedFuture(null);
|
||||
return taskSupplier.get();
|
||||
});
|
||||
|
||||
final RegistrationRecoveryPasswordsManager registrationRecoveryPasswordsManager =
|
||||
@@ -217,8 +214,7 @@ class AccountsManagerTest {
|
||||
|
||||
when(registrationRecoveryPasswordsManager.removeForNumber(anyString())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
when(keysManager.delete(any())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(keysManager.delete(any(), anyBoolean())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(keysManager.deleteSingleUsePreKeys(any())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(messagesManager.clear(any())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(profilesManager.deleteAll(any())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
@@ -959,7 +955,10 @@ class AccountsManagerTest {
|
||||
|
||||
Account account = AccountsHelper.generateTestAccount("+14152222222", List.of(primaryDevice, linkedDevice));
|
||||
|
||||
when(keysManager.delete(any(), anyByte())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(accounts.getByAccountIdentifierAsync(account.getUuid()))
|
||||
.thenReturn(CompletableFuture.completedFuture(Optional.of(account)));
|
||||
|
||||
when(keysManager.deleteSingleUsePreKeys(any(), anyByte())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(messagesManager.clear(any(), anyByte())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
assertTrue(account.getDevice(linkedDevice.getId()).isPresent());
|
||||
@@ -968,7 +967,7 @@ class AccountsManagerTest {
|
||||
|
||||
assertFalse(account.getDevice(linkedDevice.getId()).isPresent());
|
||||
verify(messagesManager, times(2)).clear(account.getUuid(), linkedDevice.getId());
|
||||
verify(keysManager).delete(account.getUuid(), linkedDevice.getId());
|
||||
verify(keysManager, times(2)).deleteSingleUsePreKeys(account.getUuid(), linkedDevice.getId());
|
||||
verify(clientPresenceManager).disconnectPresence(account.getUuid(), linkedDevice.getId());
|
||||
}
|
||||
|
||||
@@ -979,14 +978,14 @@ class AccountsManagerTest {
|
||||
|
||||
final Account account = AccountsHelper.generateTestAccount("+14152222222", List.of(primaryDevice));
|
||||
|
||||
when(keysManager.delete(any(), anyByte())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(keysManager.deleteSingleUsePreKeys(any(), anyByte())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(messagesManager.clear(any(), anyByte())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> accountsManager.removeDevice(account, Device.PRIMARY_ID));
|
||||
|
||||
assertDoesNotThrow(() -> account.getPrimaryDevice());
|
||||
assertDoesNotThrow(account::getPrimaryDevice);
|
||||
verify(messagesManager, never()).clear(any(), anyByte());
|
||||
verify(keysManager, never()).delete(any(), anyByte());
|
||||
verify(keysManager, never()).deleteSingleUsePreKeys(any(), anyByte());
|
||||
verify(clientPresenceManager, never()).disconnectPresence(any(), anyByte());
|
||||
}
|
||||
|
||||
@@ -1035,10 +1034,8 @@ class AccountsManagerTest {
|
||||
verify(accounts)
|
||||
.create(argThat(account -> e164.equals(account.getNumber()) && existingUuid.equals(account.getUuid())), any());
|
||||
|
||||
verify(keysManager).delete(existingUuid);
|
||||
verify(keysManager).delete(phoneNumberIdentifiersByE164.get(e164));
|
||||
verify(keysManager).delete(existingUuid, true);
|
||||
verify(keysManager).delete(phoneNumberIdentifiersByE164.get(e164), true);
|
||||
verify(keysManager, times(2)).deleteSingleUsePreKeys(existingUuid);
|
||||
verify(keysManager, times(2)).deleteSingleUsePreKeys(phoneNumberIdentifiersByE164.get(e164));
|
||||
verify(messagesManager, times(2)).clear(existingUuid);
|
||||
verify(profilesManager, times(2)).deleteAll(existingUuid);
|
||||
verify(clientPresenceManager).disconnectAllPresencesForUuid(existingUuid);
|
||||
@@ -1060,7 +1057,7 @@ class AccountsManagerTest {
|
||||
argThat(a -> e164.equals(a.getNumber()) && recentlyDeletedUuid.equals(a.getUuid())),
|
||||
any());
|
||||
|
||||
verify(keysManager).buildWriteItemsForRepeatedUseKeys(eq(account.getIdentifier(IdentityType.ACI)),
|
||||
verify(keysManager).buildWriteItemsForNewDevice(eq(account.getIdentifier(IdentityType.ACI)),
|
||||
eq(account.getIdentifier(IdentityType.PNI)),
|
||||
eq(Device.PRIMARY_ID),
|
||||
any(),
|
||||
@@ -1119,7 +1116,7 @@ class AccountsManagerTest {
|
||||
final KEMSignedPreKey aciPqLastResortPreKey = KeysHelper.signedKEMPreKey(3, aciKeyPair);
|
||||
final KEMSignedPreKey pniPqLastResortPreKey = KeysHelper.signedKEMPreKey(4, pniKeyPair);
|
||||
|
||||
when(keysManager.delete(any(), anyByte())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(keysManager.deleteSingleUsePreKeys(any(), anyByte())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(messagesManager.clear(any(), anyByte())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(accounts.getByAccountIdentifierAsync(aci)).thenReturn(CompletableFuture.completedFuture(Optional.of(account)));
|
||||
when(accounts.updateTransactionallyAsync(any(), any())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
@@ -1142,11 +1139,11 @@ class AccountsManagerTest {
|
||||
pniPqLastResortPreKey))
|
||||
.join();
|
||||
|
||||
verify(keysManager).delete(aci, nextDeviceId);
|
||||
verify(keysManager).delete(pni, nextDeviceId);
|
||||
verify(keysManager).deleteSingleUsePreKeys(aci, nextDeviceId);
|
||||
verify(keysManager).deleteSingleUsePreKeys(pni, nextDeviceId);
|
||||
verify(messagesManager).clear(aci, nextDeviceId);
|
||||
|
||||
verify(keysManager).buildWriteItemsForRepeatedUseKeys(
|
||||
verify(keysManager).buildWriteItemsForNewDevice(
|
||||
aci,
|
||||
pni,
|
||||
nextDeviceId,
|
||||
@@ -1207,8 +1204,8 @@ class AccountsManagerTest {
|
||||
|
||||
assertTrue(phoneNumberIdentifiersByE164.containsKey(targetNumber));
|
||||
|
||||
verify(keysManager).delete(originalPni);
|
||||
verify(keysManager).delete(phoneNumberIdentifiersByE164.get(targetNumber));
|
||||
verify(keysManager).deleteSingleUsePreKeys(originalPni);
|
||||
verify(keysManager).deleteSingleUsePreKeys(phoneNumberIdentifiersByE164.get(targetNumber));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1219,7 +1216,7 @@ class AccountsManagerTest {
|
||||
account = accountsManager.changeNumber(account, number, null, null, null, null);
|
||||
|
||||
assertEquals(number, account.getNumber());
|
||||
verify(keysManager, never()).delete(any());
|
||||
verify(keysManager, never()).deleteSingleUsePreKeys(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1258,10 +1255,10 @@ class AccountsManagerTest {
|
||||
assertTrue(phoneNumberIdentifiersByE164.containsKey(targetNumber));
|
||||
final UUID newPni = phoneNumberIdentifiersByE164.get(targetNumber);
|
||||
|
||||
verify(keysManager).delete(existingAccountUuid);
|
||||
verify(keysManager).delete(originalPni);
|
||||
verify(keysManager, atLeastOnce()).delete(targetPni);
|
||||
verify(keysManager).delete(newPni);
|
||||
verify(keysManager).deleteSingleUsePreKeys(existingAccountUuid);
|
||||
verify(keysManager).deleteSingleUsePreKeys(originalPni);
|
||||
verify(keysManager, atLeastOnce()).deleteSingleUsePreKeys(targetPni);
|
||||
verify(keysManager).deleteSingleUsePreKeys(newPni);
|
||||
verifyNoMoreInteractions(keysManager);
|
||||
}
|
||||
|
||||
@@ -1302,10 +1299,10 @@ class AccountsManagerTest {
|
||||
assertTrue(phoneNumberIdentifiersByE164.containsKey(targetNumber));
|
||||
|
||||
final UUID newPni = phoneNumberIdentifiersByE164.get(targetNumber);
|
||||
verify(keysManager).delete(existingAccountUuid);
|
||||
verify(keysManager, atLeastOnce()).delete(targetPni);
|
||||
verify(keysManager).delete(newPni);
|
||||
verify(keysManager).delete(originalPni);
|
||||
verify(keysManager).deleteSingleUsePreKeys(existingAccountUuid);
|
||||
verify(keysManager, atLeastOnce()).deleteSingleUsePreKeys(targetPni);
|
||||
verify(keysManager).deleteSingleUsePreKeys(newPni);
|
||||
verify(keysManager).deleteSingleUsePreKeys(originalPni);
|
||||
verify(keysManager).getPqEnabledDevices(uuid);
|
||||
verify(keysManager).buildWriteItemForEcSignedPreKey(eq(newPni), eq(Device.PRIMARY_ID), any());
|
||||
verify(keysManager).buildWriteItemForEcSignedPreKey(eq(newPni), eq(deviceId2), any());
|
||||
@@ -1408,7 +1405,7 @@ class AccountsManagerTest {
|
||||
|
||||
verify(accounts).updateTransactionallyAsync(any(), any());
|
||||
|
||||
verify(keysManager).delete(oldPni);
|
||||
verify(keysManager).deleteSingleUsePreKeys(oldPni);
|
||||
verify(keysManager).buildWriteItemForEcSignedPreKey(eq(oldPni), eq(Device.PRIMARY_ID), any());
|
||||
verify(keysManager).buildWriteItemForEcSignedPreKey(eq(oldPni), eq(deviceId2), any());
|
||||
verify(keysManager, never()).buildWriteItemForLastResortKey(any(), anyByte(), any());
|
||||
@@ -1471,7 +1468,7 @@ class AccountsManagerTest {
|
||||
|
||||
verify(accounts).updateTransactionallyAsync(any(), any());
|
||||
|
||||
verify(keysManager).delete(oldPni);
|
||||
verify(keysManager).deleteSingleUsePreKeys(oldPni);
|
||||
verify(keysManager).buildWriteItemForEcSignedPreKey(eq(oldPni), eq(Device.PRIMARY_ID), any());
|
||||
verify(keysManager).buildWriteItemForEcSignedPreKey(eq(oldPni), eq(deviceId2), any());
|
||||
verify(keysManager).buildWriteItemForLastResortKey(eq(oldPni), eq(Device.PRIMARY_ID), any());
|
||||
@@ -1534,7 +1531,7 @@ class AccountsManagerTest {
|
||||
|
||||
verify(accounts).updateTransactionallyAsync(any(), any());
|
||||
|
||||
verify(keysManager).delete(oldPni);
|
||||
verify(keysManager).deleteSingleUsePreKeys(oldPni);
|
||||
verify(keysManager).buildWriteItemForEcSignedPreKey(eq(oldPni), eq(Device.PRIMARY_ID), any());
|
||||
verify(keysManager).buildWriteItemForEcSignedPreKey(eq(oldPni), eq(deviceId2), any());
|
||||
verify(keysManager, never()).buildWriteItemForLastResortKey(any(), anyByte(), any());
|
||||
|
||||
@@ -202,7 +202,7 @@ class AccountsTest {
|
||||
assertPhoneNumberConstraintExists("+14151112222", account.getUuid());
|
||||
assertPhoneNumberIdentifierConstraintExists(account.getPhoneNumberIdentifier(), account.getUuid());
|
||||
|
||||
accounts.delete(originalUuid).join();
|
||||
accounts.delete(originalUuid, Collections.emptyList()).join();
|
||||
assertThat(accounts.findRecentlyDeletedAccountIdentifier(account.getNumber())).hasValue(originalUuid);
|
||||
|
||||
freshUser = createAccount(account);
|
||||
@@ -679,7 +679,7 @@ class AccountsTest {
|
||||
assertThat(accounts.getByAccountIdentifier(deletedAccount.getUuid())).isPresent();
|
||||
assertThat(accounts.getByAccountIdentifier(retainedAccount.getUuid())).isPresent();
|
||||
|
||||
accounts.delete(deletedAccount.getUuid()).join();
|
||||
accounts.delete(deletedAccount.getUuid(), Collections.emptyList()).join();
|
||||
|
||||
assertThat(accounts.getByAccountIdentifier(deletedAccount.getUuid())).isNotPresent();
|
||||
assertThat(accounts.findRecentlyDeletedAccountIdentifier(deletedAccount.getNumber())).hasValue(deletedAccount.getUuid());
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package org.whispersystems.textsecuregcm.storage;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyByte;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -12,7 +15,9 @@ import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -23,7 +28,9 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.signal.libsignal.protocol.ecc.Curve;
|
||||
import org.signal.libsignal.protocol.ecc.ECKeyPair;
|
||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicECPreKeyMigrationConfiguration;
|
||||
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
||||
import org.whispersystems.textsecuregcm.identity.IdentityType;
|
||||
import org.whispersystems.textsecuregcm.push.ClientPresenceManager;
|
||||
import org.whispersystems.textsecuregcm.redis.RedisClusterExtension;
|
||||
import org.whispersystems.textsecuregcm.securestorage.SecureStorageClient;
|
||||
@@ -32,7 +39,7 @@ import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
|
||||
import org.whispersystems.textsecuregcm.tests.util.KeysHelper;
|
||||
import org.whispersystems.textsecuregcm.util.Pair;
|
||||
|
||||
public class LinkDeviceIntegrationTest {
|
||||
public class AddRemoveDeviceIntegrationTest {
|
||||
|
||||
@RegisterExtension
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(
|
||||
@@ -56,16 +63,19 @@ public class LinkDeviceIntegrationTest {
|
||||
private ExecutorService accountLockExecutor;
|
||||
private ExecutorService clientPresenceExecutor;
|
||||
|
||||
private AccountsManager accountsManager;
|
||||
private KeysManager keysManager;
|
||||
private MessagesManager messagesManager;
|
||||
private AccountsManager accountsManager;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
@SuppressWarnings("unchecked") final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager =
|
||||
mock(DynamicConfigurationManager.class);
|
||||
|
||||
DynamicConfiguration dynamicConfiguration = new DynamicConfiguration();
|
||||
final DynamicConfiguration dynamicConfiguration = mock(DynamicConfiguration.class);
|
||||
when(dynamicConfigurationManager.getConfiguration()).thenReturn(dynamicConfiguration);
|
||||
when(dynamicConfiguration.getEcPreKeyMigrationConfiguration())
|
||||
.thenReturn(new DynamicECPreKeyMigrationConfiguration(true, true));
|
||||
|
||||
keysManager = new KeysManager(
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient(),
|
||||
@@ -100,7 +110,7 @@ public class LinkDeviceIntegrationTest {
|
||||
new PhoneNumberIdentifiers(DYNAMO_DB_EXTENSION.getDynamoDbClient(),
|
||||
DynamoDbExtensionSchema.Tables.PNI.tableName());
|
||||
|
||||
final MessagesManager messagesManager = mock(MessagesManager.class);
|
||||
messagesManager = mock(MessagesManager.class);
|
||||
when(messagesManager.clear(any(), anyByte())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
final ProfilesManager profilesManager = mock(ProfilesManager.class);
|
||||
@@ -143,7 +153,7 @@ public class LinkDeviceIntegrationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void linkDevice() throws InterruptedException {
|
||||
void addDevice() throws InterruptedException {
|
||||
final String number = PhoneNumberUtil.getInstance().format(
|
||||
PhoneNumberUtil.getInstance().getExampleNumber("US"),
|
||||
PhoneNumberUtil.PhoneNumberFormat.E164);
|
||||
@@ -176,5 +186,113 @@ public class LinkDeviceIntegrationTest {
|
||||
assertEquals(2,
|
||||
accountsManager.getByAccountIdentifier(updatedAccountAndDevice.first().getUuid()).orElseThrow().getDevices()
|
||||
.size());
|
||||
|
||||
final byte addedDeviceId = updatedAccountAndDevice.second().getId();
|
||||
|
||||
assertTrue(keysManager.getEcSignedPreKey(updatedAccountAndDevice.first().getUuid(), addedDeviceId).join().isPresent());
|
||||
assertTrue(keysManager.getEcSignedPreKey(updatedAccountAndDevice.first().getPhoneNumberIdentifier(), addedDeviceId).join().isPresent());
|
||||
assertTrue(keysManager.getLastResort(updatedAccountAndDevice.first().getUuid(), addedDeviceId).join().isPresent());
|
||||
assertTrue(keysManager.getLastResort(updatedAccountAndDevice.first().getPhoneNumberIdentifier(), addedDeviceId).join().isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
void removeDevice() throws InterruptedException {
|
||||
final String number = PhoneNumberUtil.getInstance().format(
|
||||
PhoneNumberUtil.getInstance().getExampleNumber("US"),
|
||||
PhoneNumberUtil.PhoneNumberFormat.E164);
|
||||
|
||||
final ECKeyPair aciKeyPair = Curve.generateKeyPair();
|
||||
final ECKeyPair pniKeyPair = Curve.generateKeyPair();
|
||||
|
||||
final Account account = AccountsHelper.createAccount(accountsManager, number);
|
||||
assertEquals(1, accountsManager.getByAccountIdentifier(account.getUuid()).orElseThrow().getDevices().size());
|
||||
|
||||
final Pair<Account, Device> updatedAccountAndDevice =
|
||||
accountsManager.addDevice(account, new DeviceSpec(
|
||||
"device-name".getBytes(StandardCharsets.UTF_8),
|
||||
"password",
|
||||
"OWT",
|
||||
new Device.DeviceCapabilities(true, true, true, true),
|
||||
1,
|
||||
2,
|
||||
true,
|
||||
Optional.empty(),
|
||||
Optional.empty(),
|
||||
KeysHelper.signedECPreKey(1, aciKeyPair),
|
||||
KeysHelper.signedECPreKey(2, pniKeyPair),
|
||||
KeysHelper.signedKEMPreKey(3, aciKeyPair),
|
||||
KeysHelper.signedKEMPreKey(4, pniKeyPair)))
|
||||
.join();
|
||||
|
||||
final byte addedDeviceId = updatedAccountAndDevice.second().getId();
|
||||
|
||||
final Account updatedAccount = accountsManager.removeDevice(updatedAccountAndDevice.first(), addedDeviceId).join();
|
||||
|
||||
assertEquals(1, updatedAccount.getDevices().size());
|
||||
|
||||
assertFalse(keysManager.getEcSignedPreKey(updatedAccount.getUuid(), addedDeviceId).join().isPresent());
|
||||
assertFalse(keysManager.getEcSignedPreKey(updatedAccount.getPhoneNumberIdentifier(), addedDeviceId).join().isPresent());
|
||||
assertFalse(keysManager.getLastResort(updatedAccount.getUuid(), addedDeviceId).join().isPresent());
|
||||
assertFalse(keysManager.getLastResort(updatedAccount.getPhoneNumberIdentifier(), addedDeviceId).join().isPresent());
|
||||
|
||||
assertTrue(keysManager.getEcSignedPreKey(updatedAccount.getUuid(), Device.PRIMARY_ID).join().isPresent());
|
||||
assertTrue(keysManager.getEcSignedPreKey(updatedAccount.getPhoneNumberIdentifier(), Device.PRIMARY_ID).join().isPresent());
|
||||
assertTrue(keysManager.getLastResort(updatedAccount.getUuid(), Device.PRIMARY_ID).join().isPresent());
|
||||
assertTrue(keysManager.getLastResort(updatedAccount.getPhoneNumberIdentifier(), Device.PRIMARY_ID).join().isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
void removeDevicePartialFailure() throws InterruptedException {
|
||||
final String number = PhoneNumberUtil.getInstance().format(
|
||||
PhoneNumberUtil.getInstance().getExampleNumber("US"),
|
||||
PhoneNumberUtil.PhoneNumberFormat.E164);
|
||||
|
||||
final ECKeyPair aciKeyPair = Curve.generateKeyPair();
|
||||
final ECKeyPair pniKeyPair = Curve.generateKeyPair();
|
||||
|
||||
final Account account = AccountsHelper.createAccount(accountsManager, number);
|
||||
assertEquals(1, accountsManager.getByAccountIdentifier(account.getUuid()).orElseThrow().getDevices().size());
|
||||
|
||||
final UUID aci = account.getIdentifier(IdentityType.ACI);
|
||||
final UUID pni = account.getIdentifier(IdentityType.PNI);
|
||||
|
||||
final Pair<Account, Device> updatedAccountAndDevice =
|
||||
accountsManager.addDevice(account, new DeviceSpec(
|
||||
"device-name".getBytes(StandardCharsets.UTF_8),
|
||||
"password",
|
||||
"OWT",
|
||||
new Device.DeviceCapabilities(true, true, true, true),
|
||||
1,
|
||||
2,
|
||||
true,
|
||||
Optional.empty(),
|
||||
Optional.empty(),
|
||||
KeysHelper.signedECPreKey(1, aciKeyPair),
|
||||
KeysHelper.signedECPreKey(2, pniKeyPair),
|
||||
KeysHelper.signedKEMPreKey(3, aciKeyPair),
|
||||
KeysHelper.signedKEMPreKey(4, pniKeyPair)))
|
||||
.join();
|
||||
|
||||
final byte addedDeviceId = updatedAccountAndDevice.second().getId();
|
||||
|
||||
when(messagesManager.clear(any(), anyByte()))
|
||||
.thenReturn(CompletableFuture.failedFuture(new RuntimeException("OH NO")));
|
||||
|
||||
assertThrows(CompletionException.class,
|
||||
() -> accountsManager.removeDevice(updatedAccountAndDevice.first(), addedDeviceId).join());
|
||||
|
||||
final Account retrievedAccount = accountsManager.getByAccountIdentifierAsync(aci).join().orElseThrow();
|
||||
|
||||
assertEquals(2, retrievedAccount.getDevices().size());
|
||||
|
||||
assertTrue(keysManager.getEcSignedPreKey(retrievedAccount.getUuid(), addedDeviceId).join().isPresent());
|
||||
assertTrue(keysManager.getEcSignedPreKey(retrievedAccount.getPhoneNumberIdentifier(), addedDeviceId).join().isPresent());
|
||||
assertTrue(keysManager.getLastResort(retrievedAccount.getUuid(), addedDeviceId).join().isPresent());
|
||||
assertTrue(keysManager.getLastResort(retrievedAccount.getPhoneNumberIdentifier(), addedDeviceId).join().isPresent());
|
||||
|
||||
assertTrue(keysManager.getEcSignedPreKey(retrievedAccount.getUuid(), Device.PRIMARY_ID).join().isPresent());
|
||||
assertTrue(keysManager.getEcSignedPreKey(retrievedAccount.getPhoneNumberIdentifier(), Device.PRIMARY_ID).join().isPresent());
|
||||
assertTrue(keysManager.getLastResort(retrievedAccount.getUuid(), Device.PRIMARY_ID).join().isPresent());
|
||||
assertTrue(keysManager.getLastResort(retrievedAccount.getPhoneNumberIdentifier(), Device.PRIMARY_ID).join().isPresent());
|
||||
}
|
||||
}
|
||||
@@ -140,7 +140,7 @@ class KeysManagerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteByAccount() {
|
||||
void testDeleteSingleUsePreKeysByAccount() {
|
||||
int keyId = 1;
|
||||
|
||||
for (byte deviceId : new byte[] {DEVICE_ID, DEVICE_ID + 1}) {
|
||||
@@ -157,18 +157,18 @@ class KeysManagerTest {
|
||||
assertTrue(keysManager.getLastResort(ACCOUNT_UUID, deviceId).join().isPresent());
|
||||
}
|
||||
|
||||
keysManager.delete(ACCOUNT_UUID).join();
|
||||
keysManager.deleteSingleUsePreKeys(ACCOUNT_UUID).join();
|
||||
|
||||
for (byte deviceId : new byte[] {DEVICE_ID, DEVICE_ID + 1}) {
|
||||
assertEquals(0, keysManager.getEcCount(ACCOUNT_UUID, deviceId).join());
|
||||
assertEquals(0, keysManager.getPqCount(ACCOUNT_UUID, deviceId).join());
|
||||
assertFalse(keysManager.getEcSignedPreKey(ACCOUNT_UUID, deviceId).join().isPresent());
|
||||
assertFalse(keysManager.getLastResort(ACCOUNT_UUID, deviceId).join().isPresent());
|
||||
assertTrue(keysManager.getEcSignedPreKey(ACCOUNT_UUID, deviceId).join().isPresent());
|
||||
assertTrue(keysManager.getLastResort(ACCOUNT_UUID, deviceId).join().isPresent());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteByAccountAndDevice() {
|
||||
void testDeleteSingleUsePreKeysByAccountAndDevice() {
|
||||
int keyId = 1;
|
||||
|
||||
for (byte deviceId : new byte[] {DEVICE_ID, DEVICE_ID + 1}) {
|
||||
@@ -185,12 +185,12 @@ class KeysManagerTest {
|
||||
assertTrue(keysManager.getLastResort(ACCOUNT_UUID, deviceId).join().isPresent());
|
||||
}
|
||||
|
||||
keysManager.delete(ACCOUNT_UUID, DEVICE_ID).join();
|
||||
keysManager.deleteSingleUsePreKeys(ACCOUNT_UUID, DEVICE_ID).join();
|
||||
|
||||
assertEquals(0, keysManager.getEcCount(ACCOUNT_UUID, DEVICE_ID).join());
|
||||
assertEquals(0, keysManager.getPqCount(ACCOUNT_UUID, DEVICE_ID).join());
|
||||
assertFalse(keysManager.getEcSignedPreKey(ACCOUNT_UUID, DEVICE_ID).join().isPresent());
|
||||
assertFalse(keysManager.getLastResort(ACCOUNT_UUID, DEVICE_ID).join().isPresent());
|
||||
assertTrue(keysManager.getEcSignedPreKey(ACCOUNT_UUID, DEVICE_ID).join().isPresent());
|
||||
assertTrue(keysManager.getLastResort(ACCOUNT_UUID, DEVICE_ID).join().isPresent());
|
||||
|
||||
assertEquals(1, keysManager.getEcCount(ACCOUNT_UUID, (byte) (DEVICE_ID + 1)).join());
|
||||
assertEquals(1, keysManager.getPqCount(ACCOUNT_UUID, (byte) (DEVICE_ID + 1)).join());
|
||||
|
||||
@@ -276,7 +276,7 @@ class MessagePersisterTest {
|
||||
|
||||
when(messagesManager.persistMessages(any(UUID.class), anyByte(), anyList())).thenThrow(ItemCollectionSizeLimitExceededException.builder().build());
|
||||
when(messagesManager.clear(any(UUID.class), anyByte())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(keysManager.delete(any(), eq(inactiveId))).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(keysManager.deleteSingleUsePreKeys(any(), eq(inactiveId))).thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
assertTimeoutPreemptively(Duration.ofSeconds(1), () ->
|
||||
messagePersister.persistQueue(destinationAccount, DESTINATION_DEVICE_ID));
|
||||
@@ -326,7 +326,7 @@ class MessagePersisterTest {
|
||||
|
||||
when(messagesManager.persistMessages(any(UUID.class), anyByte(), anyList())).thenThrow(ItemCollectionSizeLimitExceededException.builder().build());
|
||||
when(messagesManager.clear(any(UUID.class), anyByte())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(keysManager.delete(any(), eq(deviceIdB))).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(keysManager.deleteSingleUsePreKeys(any(), eq(deviceIdB))).thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
assertTimeoutPreemptively(Duration.ofSeconds(1), () ->
|
||||
messagePersister.persistQueue(destinationAccount, DESTINATION_DEVICE_ID));
|
||||
@@ -376,7 +376,7 @@ class MessagePersisterTest {
|
||||
|
||||
when(messagesManager.persistMessages(any(UUID.class), anyByte(), anyList())).thenThrow(ItemCollectionSizeLimitExceededException.builder().build());
|
||||
when(messagesManager.clear(any(UUID.class), anyByte())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(keysManager.delete(any(), anyByte())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(keysManager.deleteSingleUsePreKeys(any(), anyByte())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
assertTimeoutPreemptively(Duration.ofSeconds(1), () ->
|
||||
messagePersister.persistQueue(destinationAccount, DESTINATION_DEVICE_ID));
|
||||
|
||||
@@ -18,6 +18,7 @@ import org.signal.libsignal.protocol.ecc.Curve;
|
||||
import org.signal.libsignal.protocol.ecc.ECKeyPair;
|
||||
import org.whispersystems.textsecuregcm.entities.ECSignedPreKey;
|
||||
import org.whispersystems.textsecuregcm.tests.util.KeysHelper;
|
||||
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
|
||||
|
||||
class RepeatedUseECSignedPreKeyStoreTest extends RepeatedUseSignedPreKeyStoreTest<ECSignedPreKey> {
|
||||
|
||||
@@ -47,6 +48,11 @@ class RepeatedUseECSignedPreKeyStoreTest extends RepeatedUseSignedPreKeyStoreTes
|
||||
return KeysHelper.signedECPreKey(currentKeyId++, IDENTITY_KEY_PAIR);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DynamoDbClient getDynamoDbClient() {
|
||||
return DYNAMO_DB_EXTENSION.getDynamoDbClient();
|
||||
}
|
||||
|
||||
@Test
|
||||
void storeIfAbsent() {
|
||||
final UUID identifier = UUID.randomUUID();
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.signal.libsignal.protocol.ecc.Curve;
|
||||
import org.signal.libsignal.protocol.ecc.ECKeyPair;
|
||||
import org.whispersystems.textsecuregcm.entities.KEMSignedPreKey;
|
||||
import org.whispersystems.textsecuregcm.tests.util.KeysHelper;
|
||||
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
|
||||
|
||||
class RepeatedUseKEMSignedPreKeyStoreTest extends RepeatedUseSignedPreKeyStoreTest<KEMSignedPreKey> {
|
||||
|
||||
@@ -35,6 +36,11 @@ class RepeatedUseKEMSignedPreKeyStoreTest extends RepeatedUseSignedPreKeyStoreTe
|
||||
return keyStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DynamoDbClient getDynamoDbClient() {
|
||||
return DYNAMO_DB_EXTENSION.getDynamoDbClient();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected KEMSignedPreKey generateSignedPreKey() {
|
||||
return KeysHelper.signedKEMPreKey(currentKeyId++, IDENTITY_KEY_PAIR);
|
||||
|
||||
@@ -5,16 +5,16 @@
|
||||
|
||||
package org.whispersystems.textsecuregcm.storage;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.whispersystems.textsecuregcm.entities.SignedPreKey;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.whispersystems.textsecuregcm.entities.SignedPreKey;
|
||||
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
|
||||
import software.amazon.awssdk.services.dynamodb.model.TransactWriteItemsRequest;
|
||||
|
||||
abstract class RepeatedUseSignedPreKeyStoreTest<K extends SignedPreKey<?>> {
|
||||
|
||||
@@ -22,6 +22,8 @@ abstract class RepeatedUseSignedPreKeyStoreTest<K extends SignedPreKey<?>> {
|
||||
|
||||
protected abstract K generateSignedPreKey();
|
||||
|
||||
protected abstract DynamoDbClient getDynamoDbClient();
|
||||
|
||||
@Test
|
||||
void storeFind() {
|
||||
final RepeatedUseSignedPreKeyStore<K> keys = getKeyStore();
|
||||
@@ -52,7 +54,23 @@ abstract class RepeatedUseSignedPreKeyStoreTest<K extends SignedPreKey<?>> {
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteForDevice() {
|
||||
void buildTransactWriteItemForInsertion() {
|
||||
final RepeatedUseSignedPreKeyStore<K> keys = getKeyStore();
|
||||
|
||||
assertEquals(Optional.empty(), keys.find(UUID.randomUUID(), Device.PRIMARY_ID).join());
|
||||
|
||||
final UUID identifier = UUID.randomUUID();
|
||||
final K signedPreKey = generateSignedPreKey();
|
||||
|
||||
getDynamoDbClient().transactWriteItems(TransactWriteItemsRequest.builder()
|
||||
.transactItems(keys.buildTransactWriteItemForInsertion(identifier, Device.PRIMARY_ID, signedPreKey))
|
||||
.build());
|
||||
|
||||
assertEquals(Optional.of(signedPreKey), keys.find(identifier, Device.PRIMARY_ID).join());
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildTransactWriteItemForDeletion() {
|
||||
final RepeatedUseSignedPreKeyStore<K> keys = getKeyStore();
|
||||
|
||||
final UUID identifier = UUID.randomUUID();
|
||||
@@ -63,36 +81,12 @@ abstract class RepeatedUseSignedPreKeyStoreTest<K extends SignedPreKey<?>> {
|
||||
);
|
||||
|
||||
keys.store(identifier, signedPreKeys).join();
|
||||
keys.delete(identifier, Device.PRIMARY_ID).join();
|
||||
|
||||
getDynamoDbClient().transactWriteItems(TransactWriteItemsRequest.builder()
|
||||
.transactItems(keys.buildTransactWriteItemForDeletion(identifier, Device.PRIMARY_ID))
|
||||
.build());
|
||||
|
||||
assertEquals(Optional.empty(), keys.find(identifier, Device.PRIMARY_ID).join());
|
||||
assertEquals(Optional.of(signedPreKeys.get(deviceId2)), keys.find(identifier, deviceId2).join());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void deleteForAllDevices(final boolean excludePrimaryDevice) {
|
||||
final RepeatedUseSignedPreKeyStore<K> keys = getKeyStore();
|
||||
|
||||
assertDoesNotThrow(() -> keys.delete(UUID.randomUUID(), excludePrimaryDevice).join());
|
||||
|
||||
final byte deviceId2 = Device.PRIMARY_ID + 1;
|
||||
|
||||
final UUID identifier = UUID.randomUUID();
|
||||
final Map<Byte, K> signedPreKeys = Map.of(
|
||||
Device.PRIMARY_ID, generateSignedPreKey(),
|
||||
deviceId2, generateSignedPreKey()
|
||||
);
|
||||
|
||||
keys.store(identifier, signedPreKeys).join();
|
||||
keys.delete(identifier, excludePrimaryDevice).join();
|
||||
|
||||
if (excludePrimaryDevice) {
|
||||
assertTrue(keys.find(identifier, Device.PRIMARY_ID).join().isPresent());
|
||||
} else {
|
||||
assertEquals(Optional.empty(), keys.find(identifier, Device.PRIMARY_ID).join());
|
||||
}
|
||||
|
||||
assertEquals(Optional.empty(), keys.find(identifier, deviceId2).join());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user