mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-21 12:28:05 +01:00
Remove "no action on change to same number" optimization for "change number" operations
This commit is contained in:
committed by
Jon Chambers
parent
e62b3d390f
commit
a36fba061a
@@ -1019,10 +1019,15 @@ class AccountsManagerTest {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testChangePhoneNumber() throws InterruptedException, MismatchedDevicesException {
|
||||
final String originalNumber = "+14152222222";
|
||||
final String targetNumber = "+14153333333";
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"+14152222222,+14153333333",
|
||||
|
||||
// Historically, "change number" behavior was different for "change to existing number," though that's no longer
|
||||
// the case
|
||||
"+14152222222,+14152222222"
|
||||
})
|
||||
void testChangePhoneNumber(final String originalNumber, final String targetNumber) throws InterruptedException, MismatchedDevicesException {
|
||||
final UUID uuid = UUID.randomUUID();
|
||||
final UUID originalPni = UUID.randomUUID();
|
||||
final ECKeyPair pniIdentityKeyPair = Curve.generateKeyPair();
|
||||
@@ -1048,33 +1053,17 @@ class AccountsManagerTest {
|
||||
verify(keysManager).buildWriteItemForLastResortKey(phoneNumberIdentifiersByE164.get(targetNumber), Device.PRIMARY_ID, kemLastResortPreKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testChangePhoneNumberSameNumber() throws InterruptedException, MismatchedDevicesException {
|
||||
final String number = "+14152222222";
|
||||
final ECKeyPair pniIdentityKeyPair = Curve.generateKeyPair();
|
||||
|
||||
Account account = AccountsHelper.generateTestAccount(number, UUID.randomUUID(), UUID.randomUUID(), List.of(DevicesHelper.createDevice(Device.PRIMARY_ID)), new byte[UnidentifiedAccessUtil.UNIDENTIFIED_ACCESS_KEY_LENGTH]);
|
||||
phoneNumberIdentifiersByE164.put(number, account.getPhoneNumberIdentifier());
|
||||
account = accountsManager.changeNumber(account,
|
||||
number,
|
||||
new IdentityKey(pniIdentityKeyPair.getPublicKey()),
|
||||
Map.of(Device.PRIMARY_ID, KeysHelper.signedECPreKey(1, pniIdentityKeyPair)),
|
||||
Map.of(Device.PRIMARY_ID, KeysHelper.signedKEMPreKey(2, pniIdentityKeyPair)),
|
||||
Map.of(Device.PRIMARY_ID, 1));
|
||||
|
||||
assertEquals(number, account.getNumber());
|
||||
verifyNoInteractions(keysManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testChangePhoneNumberDifferentNumberSamePni() throws InterruptedException, MismatchedDevicesException {
|
||||
final String originalNumber = "+22923456789";
|
||||
// the canonical form of numbers may change over time, so we use PNIs as stable identifiers
|
||||
final String newNumber = "+2290123456789";
|
||||
final ECKeyPair pniIdentityKeyPair = Curve.generateKeyPair();
|
||||
final UUID phoneNumberIdentifier = UUID.randomUUID();
|
||||
|
||||
Account account = AccountsHelper.generateTestAccount(originalNumber, UUID.randomUUID(), phoneNumberIdentifier,
|
||||
List.of(DevicesHelper.createDevice(Device.PRIMARY_ID)), new byte[UnidentifiedAccessUtil.UNIDENTIFIED_ACCESS_KEY_LENGTH]);
|
||||
|
||||
Account account = AccountsHelper.generateTestAccount(originalNumber, UUID.randomUUID(), UUID.randomUUID(),
|
||||
new ArrayList<>(), new byte[UnidentifiedAccessUtil.UNIDENTIFIED_ACCESS_KEY_LENGTH]);
|
||||
phoneNumberIdentifiersByE164.put(originalNumber, account.getPhoneNumberIdentifier());
|
||||
phoneNumberIdentifiersByE164.put(newNumber, account.getPhoneNumberIdentifier());
|
||||
account = accountsManager.changeNumber(account,
|
||||
@@ -1084,8 +1073,9 @@ class AccountsManagerTest {
|
||||
Map.of(Device.PRIMARY_ID, KeysHelper.signedKEMPreKey(2, pniIdentityKeyPair)),
|
||||
Map.of(Device.PRIMARY_ID, 1));
|
||||
|
||||
assertEquals(originalNumber, account.getNumber());
|
||||
verifyNoInteractions(keysManager);
|
||||
assertEquals(newNumber, account.getNumber());
|
||||
assertEquals(phoneNumberIdentifier, account.getIdentifier(IdentityType.PNI));
|
||||
verify(accounts, never()).delete(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
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.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyByte;
|
||||
@@ -245,153 +244,6 @@ public class ChangeNumberManagerTest {
|
||||
assertEquals(updatedPhoneNumberIdentifiersByAccount.get(account), UUID.fromString(envelope.getUpdatedPni()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void changeNumberSameNumberSetPrimaryDevicePrekeyAndSendMessages() throws Exception {
|
||||
final String originalE164 = "+18005551234";
|
||||
final UUID aci = UUID.randomUUID();
|
||||
final UUID pni = UUID.randomUUID();
|
||||
|
||||
final Account account = mock(Account.class);
|
||||
when(account.getNumber()).thenReturn(originalE164);
|
||||
when(account.getUuid()).thenReturn(aci);
|
||||
when(account.getPhoneNumberIdentifier()).thenReturn(pni);
|
||||
|
||||
final Device d2 = mock(Device.class);
|
||||
final byte deviceId2 = 2;
|
||||
when(d2.getId()).thenReturn(deviceId2);
|
||||
|
||||
when(account.getDevice(deviceId2)).thenReturn(Optional.of(d2));
|
||||
when(account.getDevices()).thenReturn(List.of(d2));
|
||||
|
||||
final ECKeyPair pniIdentityKeyPair = Curve.generateKeyPair();
|
||||
final IdentityKey pniIdentityKey = new IdentityKey(pniIdentityKeyPair.getPublicKey());
|
||||
final Map<Byte, ECSignedPreKey> prekeys = Map.of(Device.PRIMARY_ID,
|
||||
KeysHelper.signedECPreKey(1, pniIdentityKeyPair),
|
||||
deviceId2, KeysHelper.signedECPreKey(2, pniIdentityKeyPair));
|
||||
final Map<Byte, KEMSignedPreKey> pqPrekeys = Map.of((byte) 3, KeysHelper.signedKEMPreKey(3, pniIdentityKeyPair),
|
||||
(byte) 4, KeysHelper.signedKEMPreKey(4, pniIdentityKeyPair));
|
||||
final Map<Byte, Integer> registrationIds = Map.of(Device.PRIMARY_ID, 17, deviceId2, 19);
|
||||
|
||||
final IncomingMessage msg = mock(IncomingMessage.class);
|
||||
when(msg.destinationDeviceId()).thenReturn(deviceId2);
|
||||
when(msg.content()).thenReturn(new byte[]{1});
|
||||
|
||||
changeNumberManager.changeNumber(account, originalE164, pniIdentityKey, prekeys, pqPrekeys, List.of(msg), registrationIds, null);
|
||||
|
||||
verify(accountsManager).updatePniKeys(account, pniIdentityKey, prekeys, pqPrekeys, registrationIds);
|
||||
|
||||
@SuppressWarnings("unchecked") final ArgumentCaptor<Map<Byte, MessageProtos.Envelope>> envelopeCaptor =
|
||||
ArgumentCaptor.forClass(Map.class);
|
||||
|
||||
verify(messageSender).sendMessages(any(), any(), envelopeCaptor.capture(), any(), any(), any());
|
||||
|
||||
assertEquals(1, envelopeCaptor.getValue().size());
|
||||
assertEquals(Set.of(deviceId2), envelopeCaptor.getValue().keySet());
|
||||
|
||||
final MessageProtos.Envelope envelope = envelopeCaptor.getValue().get(deviceId2);
|
||||
|
||||
assertEquals(aci, UUID.fromString(envelope.getDestinationServiceId()));
|
||||
assertEquals(aci, UUID.fromString(envelope.getSourceServiceId()));
|
||||
assertEquals(Device.PRIMARY_ID, envelope.getSourceDevice());
|
||||
assertFalse(updatedPhoneNumberIdentifiersByAccount.containsKey(account));
|
||||
}
|
||||
|
||||
@Test
|
||||
void updatePniKeysSetPrimaryDevicePrekeyAndSendMessages() throws Exception {
|
||||
final UUID aci = UUID.randomUUID();
|
||||
final UUID pni = UUID.randomUUID();
|
||||
|
||||
final Account account = mock(Account.class);
|
||||
when(account.getUuid()).thenReturn(aci);
|
||||
when(account.getPhoneNumberIdentifier()).thenReturn(pni);
|
||||
|
||||
final Device d2 = mock(Device.class);
|
||||
final byte deviceId2 = 2;
|
||||
when(d2.getId()).thenReturn(deviceId2);
|
||||
|
||||
when(account.getDevice(deviceId2)).thenReturn(Optional.of(d2));
|
||||
when(account.getDevices()).thenReturn(List.of(d2));
|
||||
|
||||
final ECKeyPair pniIdentityKeyPair = Curve.generateKeyPair();
|
||||
final IdentityKey pniIdentityKey = new IdentityKey(pniIdentityKeyPair.getPublicKey());
|
||||
final Map<Byte, ECSignedPreKey> prekeys = Map.of(Device.PRIMARY_ID,
|
||||
KeysHelper.signedECPreKey(1, pniIdentityKeyPair),
|
||||
deviceId2, KeysHelper.signedECPreKey(2, pniIdentityKeyPair));
|
||||
final Map<Byte, Integer> registrationIds = Map.of(Device.PRIMARY_ID, 17, deviceId2, 19);
|
||||
|
||||
final IncomingMessage msg = mock(IncomingMessage.class);
|
||||
when(msg.destinationDeviceId()).thenReturn(deviceId2);
|
||||
when(msg.content()).thenReturn(new byte[]{1});
|
||||
|
||||
changeNumberManager.updatePniKeys(account, pniIdentityKey, prekeys, null, List.of(msg), registrationIds, null);
|
||||
|
||||
verify(accountsManager).updatePniKeys(account, pniIdentityKey, prekeys, null, registrationIds);
|
||||
|
||||
@SuppressWarnings("unchecked") final ArgumentCaptor<Map<Byte, MessageProtos.Envelope>> envelopeCaptor =
|
||||
ArgumentCaptor.forClass(Map.class);
|
||||
|
||||
verify(messageSender).sendMessages(any(), any(), envelopeCaptor.capture(), any(), any(), any());
|
||||
|
||||
assertEquals(1, envelopeCaptor.getValue().size());
|
||||
assertEquals(Set.of(deviceId2), envelopeCaptor.getValue().keySet());
|
||||
|
||||
final MessageProtos.Envelope envelope = envelopeCaptor.getValue().get(deviceId2);
|
||||
|
||||
assertEquals(aci, UUID.fromString(envelope.getDestinationServiceId()));
|
||||
assertEquals(aci, UUID.fromString(envelope.getSourceServiceId()));
|
||||
assertEquals(Device.PRIMARY_ID, envelope.getSourceDevice());
|
||||
assertFalse(updatedPhoneNumberIdentifiersByAccount.containsKey(account));
|
||||
}
|
||||
|
||||
@Test
|
||||
void updatePniKeysSetPrimaryDevicePrekeyPqAndSendMessages() throws Exception {
|
||||
final UUID aci = UUID.randomUUID();
|
||||
final UUID pni = UUID.randomUUID();
|
||||
|
||||
final Account account = mock(Account.class);
|
||||
when(account.getUuid()).thenReturn(aci);
|
||||
when(account.getPhoneNumberIdentifier()).thenReturn(pni);
|
||||
|
||||
final Device d2 = mock(Device.class);
|
||||
final byte deviceId2 = 2;
|
||||
when(d2.getId()).thenReturn(deviceId2);
|
||||
|
||||
when(account.getDevice(deviceId2)).thenReturn(Optional.of(d2));
|
||||
when(account.getDevices()).thenReturn(List.of(d2));
|
||||
|
||||
final ECKeyPair pniIdentityKeyPair = Curve.generateKeyPair();
|
||||
final IdentityKey pniIdentityKey = new IdentityKey(pniIdentityKeyPair.getPublicKey());
|
||||
final Map<Byte, ECSignedPreKey> prekeys = Map.of(Device.PRIMARY_ID,
|
||||
KeysHelper.signedECPreKey(1, pniIdentityKeyPair),
|
||||
deviceId2, KeysHelper.signedECPreKey(2, pniIdentityKeyPair));
|
||||
final Map<Byte, KEMSignedPreKey> pqPrekeys = Map.of((byte) 3, KeysHelper.signedKEMPreKey(3, pniIdentityKeyPair),
|
||||
(byte) 4, KeysHelper.signedKEMPreKey(4, pniIdentityKeyPair));
|
||||
final Map<Byte, Integer> registrationIds = Map.of(Device.PRIMARY_ID, 17, deviceId2, 19);
|
||||
|
||||
final IncomingMessage msg = mock(IncomingMessage.class);
|
||||
when(msg.destinationDeviceId()).thenReturn(deviceId2);
|
||||
when(msg.content()).thenReturn(new byte[]{1});
|
||||
|
||||
changeNumberManager.updatePniKeys(account, pniIdentityKey, prekeys, pqPrekeys, List.of(msg), registrationIds, null);
|
||||
|
||||
verify(accountsManager).updatePniKeys(account, pniIdentityKey, prekeys, pqPrekeys, registrationIds);
|
||||
|
||||
@SuppressWarnings("unchecked") final ArgumentCaptor<Map<Byte, MessageProtos.Envelope>> envelopeCaptor =
|
||||
ArgumentCaptor.forClass(Map.class);
|
||||
|
||||
verify(messageSender).sendMessages(any(), any(), envelopeCaptor.capture(), any(), any(), any());
|
||||
|
||||
assertEquals(1, envelopeCaptor.getValue().size());
|
||||
assertEquals(Set.of(deviceId2), envelopeCaptor.getValue().keySet());
|
||||
|
||||
final MessageProtos.Envelope envelope = envelopeCaptor.getValue().get(deviceId2);
|
||||
|
||||
assertEquals(aci, UUID.fromString(envelope.getDestinationServiceId()));
|
||||
assertEquals(aci, UUID.fromString(envelope.getSourceServiceId()));
|
||||
assertEquals(Device.PRIMARY_ID, envelope.getSourceDevice());
|
||||
assertFalse(updatedPhoneNumberIdentifiersByAccount.containsKey(account));
|
||||
}
|
||||
|
||||
@Test
|
||||
void changeNumberMissingData() {
|
||||
final Account account = mock(Account.class);
|
||||
|
||||
Reference in New Issue
Block a user