diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountController.java index 86225ce0e..2ae19bbe9 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountController.java @@ -25,7 +25,6 @@ import java.util.Map; import java.util.Optional; import java.util.UUID; import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; import javax.annotation.Nullable; import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; @@ -87,7 +86,6 @@ import org.whispersystems.textsecuregcm.storage.AbusiveHostRules; import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.ChangeNumberManager; -import org.whispersystems.textsecuregcm.storage.ChangeNumberManager.DeviceUpdate; import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager; import org.whispersystems.textsecuregcm.storage.StoredVerificationCodeManager; @@ -410,27 +408,22 @@ public class AccountController { throw new ForbiddenException(); } - Map devices = Collections.emptyMap(); - if (request.getDeviceUpdates() != null && !request.getDeviceUpdates().isEmpty()) { - devices = request.getDeviceUpdates().entrySet().stream() - .collect(Collectors.toMap( - e -> e.getKey(), - e -> new DeviceUpdate(e.getValue().getSignedPhoneNumberIdentityPreKey(), e.getValue().getMessage(), e.getValue().getRegistrationID()))); + if (request.getDeviceSignedPrekeys() != null && !request.getDeviceSignedPrekeys().isEmpty()) { + if (request.getDeviceMessages() == null || request.getDeviceMessages().size() != request.getDeviceSignedPrekeys().size() - 1) { + // device_messages should exist and be one shorter than device_signed_prekeys, since it doesn't have the primary's key. + throw new WebApplicationException(Response.status(400).build()); + } try { // Checks that all except master ID are in device messages - List deviceMessages = devices.entrySet().stream() - .map(e -> e.getValue().message()) - .filter(e -> e != null) - .collect(Collectors.toList()); MessageValidation.validateCompleteDeviceList( - authenticatedAccount.getAccount(), deviceMessages, + authenticatedAccount.getAccount(), request.getDeviceMessages(), IncomingMessage::getDestinationDeviceId, true, Optional.of(Device.MASTER_ID)); MessageValidation.validateRegistrationIds( - authenticatedAccount.getAccount(), deviceMessages, + authenticatedAccount.getAccount(), request.getDeviceMessages(), IncomingMessage::getDestinationDeviceId, IncomingMessage::getDestinationRegistrationId); // Checks that all including master ID are in signed prekeys MessageValidation.validateCompleteDeviceList( - authenticatedAccount.getAccount(), devices.entrySet(), + authenticatedAccount.getAccount(), request.getDeviceSignedPrekeys().entrySet(), e -> e.getKey(), false, Optional.empty()); } catch (MismatchedDevicesException e) { throw new WebApplicationException(Response.status(409) @@ -444,6 +437,9 @@ public class AccountController { .entity(new StaleDevices(e.getStaleDevices())) .build()); } + } else if (request.getDeviceMessages() != null && !request.getDeviceMessages().isEmpty()) { + // device_messages shouldn't exist without device_signed_prekeys. + throw new WebApplicationException(Response.status(400).build()); } final String number = request.getNumber(); @@ -474,7 +470,8 @@ public class AccountController { final Account updatedAccount = changeNumberManager.changeNumber( authenticatedAccount.getAccount(), request.getNumber(), - devices); + Optional.ofNullable(request.getDeviceSignedPrekeys()).orElse(Collections.emptyMap()), + Optional.ofNullable(request.getDeviceMessages()).orElse(Collections.emptyList())); return new AccountIdentityResponse( updatedAccount.getUuid(), diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/entities/ChangePhoneNumberRequest.java b/service/src/main/java/org/whispersystems/textsecuregcm/entities/ChangePhoneNumberRequest.java index b884a942f..5b97e59ec 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/entities/ChangePhoneNumberRequest.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/entities/ChangePhoneNumberRequest.java @@ -9,6 +9,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import javax.annotation.Nullable; import javax.validation.constraints.NotBlank; +import java.util.List; import java.util.Map; public class ChangePhoneNumberRequest { @@ -25,48 +26,26 @@ public class ChangePhoneNumberRequest { @Nullable final String registrationLock; - @JsonProperty("deviceUpdates") + @JsonProperty("device_messages") @Nullable - final Map deviceUpdates; + final List deviceMessages; - public static class DeviceUpdate { - - private final IncomingMessage message; - private final SignedPreKey signedPhoneNumberIdentityPreKey; - private final Integer registrationID; - - @JsonCreator - public DeviceUpdate( - @JsonProperty("message") final IncomingMessage message, - @JsonProperty("signedPhoneNumberIdentityPrekey") final SignedPreKey signedPhoneNumberIdentityPreKey, - @JsonProperty("registratonId") final Integer registrationID) { - this.message = message; - this.signedPhoneNumberIdentityPreKey = signedPhoneNumberIdentityPreKey; - this.registrationID = registrationID; - } - - public IncomingMessage getMessage() { - return message; - } - - public SignedPreKey getSignedPhoneNumberIdentityPreKey() { - return signedPhoneNumberIdentityPreKey; - } - - public Integer getRegistrationID() { - return registrationID; - } - } + @JsonProperty("device_signed_prekeys") + @Nullable + final Map deviceSignedPrekeys; @JsonCreator public ChangePhoneNumberRequest(@JsonProperty("number") final String number, @JsonProperty("code") final String code, @JsonProperty("reglock") @Nullable final String registrationLock, - @JsonProperty("deviceUpdates") @Nullable final Map deviceUpdates) { + @JsonProperty("device_messages") @Nullable final List deviceMessages, + @JsonProperty("device_signed_prekeys") @Nullable final Map deviceSignedPrekeys) { + this.number = number; this.code = code; this.registrationLock = registrationLock; - this.deviceUpdates = deviceUpdates; + this.deviceMessages = deviceMessages; + this.deviceSignedPrekeys = deviceSignedPrekeys; } public String getNumber() { @@ -83,5 +62,12 @@ public class ChangePhoneNumberRequest { } @Nullable - public Map getDeviceUpdates() { return deviceUpdates; } + public List getDeviceMessages() { + return deviceMessages; + } + + @Nullable + public Map getDeviceSignedPrekeys() { + return deviceSignedPrekeys; + } } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/storage/ChangeNumberManager.java b/service/src/main/java/org/whispersystems/textsecuregcm/storage/ChangeNumberManager.java index 86a97291c..984ce8f5b 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/ChangeNumberManager.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/ChangeNumberManager.java @@ -16,6 +16,7 @@ import org.whispersystems.textsecuregcm.entities.SignedPreKey; import org.whispersystems.textsecuregcm.push.MessageSender; import org.whispersystems.textsecuregcm.push.NotPushRegisteredException; import javax.validation.constraints.NotNull; +import java.util.List; import java.util.Map; import java.util.Optional; @@ -31,13 +32,11 @@ public class ChangeNumberManager { this.accountsManager = accountsManager; } - public record DeviceUpdate(SignedPreKey signedPhoneNumberIdentityPreKey, IncomingMessage message, Integer registrationID) { - } - public Account changeNumber( @NotNull Account account, @NotNull final String number, - @NotNull final Map deviceUpdates) throws InterruptedException { + @NotNull final Map deviceSignedPrekeys, + @NotNull final List deviceMessages) throws InterruptedException { final Account updatedAccount; if (number.equals(account.getNumber())) { @@ -52,17 +51,14 @@ public class ChangeNumberManager { // This makes it so the client can resend a request they didn't get a response for (timeout, etc) // to make sure their messages sent and prekeys were updated, even if the first time around the // server crashed at/above this point. - if (deviceUpdates != null && !deviceUpdates.isEmpty()) { - for (Map.Entry entry : deviceUpdates.entrySet()) { - DeviceUpdate deviceUpdate = entry.getValue(); + if (deviceSignedPrekeys != null && !deviceSignedPrekeys.isEmpty()) { + for (Map.Entry entry : deviceSignedPrekeys.entrySet()) { accountsManager.updateDevice(updatedAccount, entry.getKey(), - device -> { - if (deviceUpdate.signedPhoneNumberIdentityPreKey() != null) device.setPhoneNumberIdentitySignedPreKey(deviceUpdate.signedPhoneNumberIdentityPreKey()); - if (deviceUpdate.registrationID() != null) device.setRegistrationId(deviceUpdate.registrationID()); - }); - if (deviceUpdate.message() != null) { - sendMessageToSelf(updatedAccount, updatedAccount.getDevice(entry.getKey()), deviceUpdate.message()); - } + d -> d.setPhoneNumberIdentitySignedPreKey(entry.getValue())); + } + + for (IncomingMessage message : deviceMessages) { + sendMessageToSelf(updatedAccount, updatedAccount.getDevice(message.getDestinationDeviceId()), message); } } return updatedAccount; diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/storage/ChangeNumberManagerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/storage/ChangeNumberManagerTest.java index 2d626e242..7c8a25c34 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/storage/ChangeNumberManagerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/storage/ChangeNumberManagerTest.java @@ -12,9 +12,9 @@ import org.mockito.stubbing.Answer; import org.whispersystems.textsecuregcm.entities.IncomingMessage; import org.whispersystems.textsecuregcm.entities.SignedPreKey; import org.whispersystems.textsecuregcm.push.MessageSender; -import org.whispersystems.textsecuregcm.storage.ChangeNumberManager.DeviceUpdate; import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -60,7 +60,7 @@ public class ChangeNumberManagerTest { void changeNumberNoMessages() throws Exception { Account account = mock(Account.class); when(account.getNumber()).thenReturn("+18005551234"); - changeNumberManager.changeNumber(account, "+18025551234", Collections.EMPTY_MAP); + changeNumberManager.changeNumber(account, "+18025551234", Collections.EMPTY_MAP, Collections.EMPTY_LIST); verify(accountsManager).changeNumber(account, "+18025551234"); verify(accountsManager, never()).updateDevice(any(), eq(1L), any()); verify(messageSender, never()).sendMessage(eq(account), any(), any(), eq(false)); @@ -70,8 +70,8 @@ public class ChangeNumberManagerTest { void changeNumberSetPrimaryDevicePrekey() throws Exception { Account account = mock(Account.class); when(account.getNumber()).thenReturn("+18005551234"); - var devices = Map.of(1L, new DeviceUpdate(new SignedPreKey(), null, null)); - changeNumberManager.changeNumber(account, "+18025551234", devices); + var prekeys = Map.of(1L, new SignedPreKey()); + changeNumberManager.changeNumber(account, "+18025551234", prekeys, Collections.EMPTY_LIST); verify(accountsManager).changeNumber(account, "+18025551234"); verify(accountsManager).updateDevice(any(), eq(1L), any()); verify(messageSender, never()).sendMessage(eq(account), any(), any(), eq(false)); @@ -84,13 +84,11 @@ public class ChangeNumberManagerTest { when(account.getUuid()).thenReturn(UUID.randomUUID()); Device d2 = mock(Device.class); when(account.getDevice(2L)).thenReturn(Optional.of(d2)); + var prekeys = Map.of(1L, new SignedPreKey(), 2L, new SignedPreKey()); IncomingMessage msg = mock(IncomingMessage.class); when(msg.getDestinationDeviceId()).thenReturn(2L); when(msg.getContent()).thenReturn(Base64.encodeBase64String(new byte[]{1})); - var devices = Map.of( - 1L, new DeviceUpdate(new SignedPreKey(), null, null), - 2L, new DeviceUpdate(new SignedPreKey(), msg, null)); - changeNumberManager.changeNumber(account, "+18025551234", devices); + changeNumberManager.changeNumber(account, "+18025551234", prekeys, List.of(msg)); verify(accountsManager).changeNumber(account, "+18025551234"); verify(accountsManager).updateDevice(any(), eq(1L), any()); verify(accountsManager).updateDevice(any(), eq(2L), any()); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/storage/DeviceTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/storage/DeviceTest.java index dfabe738e..600cfdc58 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/storage/DeviceTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/storage/DeviceTest.java @@ -30,7 +30,7 @@ class DeviceTest { private static Stream testIsEnabled() { return Stream.of( - // master fetchesMessages apnId gcmId signedPhoneNumberIdentityPreKey lastSeen expectEnabled + // master fetchesMessages apnId gcmId signedPreKey lastSeen expectEnabled Arguments.of(true, false, null, null, null, Duration.ofDays(60), false), Arguments.of(true, false, null, null, null, Duration.ofDays(1), false), Arguments.of(true, false, null, null, mock(SignedPreKey.class), Duration.ofDays(60), false), diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/AccountControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/AccountControllerTest.java index 9a41b594c..2f93b6c31 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/AccountControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/AccountControllerTest.java @@ -69,7 +69,6 @@ import org.whispersystems.textsecuregcm.entities.AccountAttributes; import org.whispersystems.textsecuregcm.entities.AccountIdentityResponse; import org.whispersystems.textsecuregcm.entities.ApnRegistrationId; import org.whispersystems.textsecuregcm.entities.ChangePhoneNumberRequest; -import org.whispersystems.textsecuregcm.entities.ChangePhoneNumberRequest.DeviceUpdate; import org.whispersystems.textsecuregcm.entities.GcmRegistrationId; import org.whispersystems.textsecuregcm.entities.IncomingMessage; import org.whispersystems.textsecuregcm.entities.RegistrationLock; @@ -251,7 +250,7 @@ class AccountControllerTest { when(accountsManager.setUsername(AuthHelper.VALID_ACCOUNT, "takenusername")) .thenThrow(new UsernameNotAvailableException()); - when(changeNumberManager.changeNumber(any(), any(), any())).thenAnswer((Answer) invocation -> { + when(changeNumberManager.changeNumber(any(), any(), any(), any())).thenAnswer((Answer) invocation -> { final Account account = invocation.getArgument(0, Account.class); final String number = invocation.getArgument(1, String.class); @@ -1249,10 +1248,10 @@ class AccountControllerTest { .target("/v1/accounts/number") .request() .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) - .put(Entity.entity(new ChangePhoneNumberRequest(number, code, null, null), + .put(Entity.entity(new ChangePhoneNumberRequest(number, code, null, null, null), MediaType.APPLICATION_JSON_TYPE), AccountIdentityResponse.class); - verify(changeNumberManager).changeNumber(eq(AuthHelper.VALID_ACCOUNT), eq(number), any()); + verify(changeNumberManager).changeNumber(eq(AuthHelper.VALID_ACCOUNT), eq(number), any(), any()); assertThat(accountIdentityResponse.getUuid()).isEqualTo(AuthHelper.VALID_UUID); assertThat(accountIdentityResponse.getNumber()).isEqualTo(number); @@ -1269,12 +1268,12 @@ class AccountControllerTest { .target("/v1/accounts/number") .request() .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) - .put(Entity.entity(new ChangePhoneNumberRequest(number, code, null, null), + .put(Entity.entity(new ChangePhoneNumberRequest(number, code, null, null, null), MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(400); assertThat(response.readEntity(String.class)).isBlank(); - verify(changeNumberManager, never()).changeNumber(any(), any(), any()); + verify(changeNumberManager, never()).changeNumber(any(), any(), any(), any()); } @Test @@ -1287,7 +1286,7 @@ class AccountControllerTest { .target("/v1/accounts/number") .request() .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) - .put(Entity.entity(new ChangePhoneNumberRequest(number, code, null, null), + .put(Entity.entity(new ChangePhoneNumberRequest(number, code, null, null, null), MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(400); @@ -1296,7 +1295,7 @@ class AccountControllerTest { assertThat(responseEntity.getOriginalNumber()).isEqualTo(number); assertThat(responseEntity.getNormalizedNumber()).isEqualTo("+447700900111"); - verify(changeNumberManager, never()).changeNumber(any(), any(), any()); + verify(changeNumberManager, never()).changeNumber(any(), any(), any(), any()); } @Test @@ -1306,10 +1305,10 @@ class AccountControllerTest { .target("/v1/accounts/number") .request() .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) - .put(Entity.entity(new ChangePhoneNumberRequest(AuthHelper.VALID_NUMBER, "567890", null, null), + .put(Entity.entity(new ChangePhoneNumberRequest(AuthHelper.VALID_NUMBER, "567890", null, null, null), MediaType.APPLICATION_JSON_TYPE), AccountIdentityResponse.class); - verify(changeNumberManager).changeNumber(eq(AuthHelper.VALID_ACCOUNT), any(), any()); + verify(changeNumberManager).changeNumber(eq(AuthHelper.VALID_ACCOUNT), any(), any(), any()); } @Test @@ -1324,11 +1323,11 @@ class AccountControllerTest { .target("/v1/accounts/number") .request() .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) - .put(Entity.entity(new ChangePhoneNumberRequest(number, code, null, null), + .put(Entity.entity(new ChangePhoneNumberRequest(number, code, null, null, null), MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(403); - verify(changeNumberManager, never()).changeNumber(any(), any(), any()); + verify(changeNumberManager, never()).changeNumber(any(), any(), any(), any()); } @Test @@ -1344,11 +1343,11 @@ class AccountControllerTest { .target("/v1/accounts/number") .request() .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) - .put(Entity.entity(new ChangePhoneNumberRequest(number, code + "-incorrect", null, null), + .put(Entity.entity(new ChangePhoneNumberRequest(number, code + "-incorrect", null, null, null), MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(403); - verify(changeNumberManager, never()).changeNumber(any(), any(), any()); + verify(changeNumberManager, never()).changeNumber(any(), any(), any(), any()); } @Test @@ -1374,11 +1373,11 @@ class AccountControllerTest { .target("/v1/accounts/number") .request() .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) - .put(Entity.entity(new ChangePhoneNumberRequest(number, code, null, null), + .put(Entity.entity(new ChangePhoneNumberRequest(number, code, null, null, null), MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(200); - verify(changeNumberManager).changeNumber(eq(AuthHelper.VALID_ACCOUNT), any(), any()); + verify(changeNumberManager).changeNumber(eq(AuthHelper.VALID_ACCOUNT), any(), any(), any()); } @Test @@ -1404,11 +1403,11 @@ class AccountControllerTest { .target("/v1/accounts/number") .request() .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) - .put(Entity.entity(new ChangePhoneNumberRequest(number, code, null, null), + .put(Entity.entity(new ChangePhoneNumberRequest(number, code, null, null, null), MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(423); - verify(changeNumberManager, never()).changeNumber(any(), any(), any()); + verify(changeNumberManager, never()).changeNumber(any(), any(), any(), any()); } @Test @@ -1436,11 +1435,11 @@ class AccountControllerTest { .target("/v1/accounts/number") .request() .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) - .put(Entity.entity(new ChangePhoneNumberRequest(number, code, reglock, null), + .put(Entity.entity(new ChangePhoneNumberRequest(number, code, reglock, null, null), MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(423); - verify(changeNumberManager, never()).changeNumber(any(), any(), any()); + verify(changeNumberManager, never()).changeNumber(any(), any(), any(), any()); } @Test @@ -1468,11 +1467,11 @@ class AccountControllerTest { .target("/v1/accounts/number") .request() .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) - .put(Entity.entity(new ChangePhoneNumberRequest(number, code, reglock, null), + .put(Entity.entity(new ChangePhoneNumberRequest(number, code, reglock, null, null), MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(200); - verify(changeNumberManager).changeNumber(eq(AuthHelper.VALID_ACCOUNT), any(), any()); + verify(changeNumberManager).changeNumber(eq(AuthHelper.VALID_ACCOUNT), any(), any(), any()); } @Test @@ -1489,14 +1488,11 @@ class AccountControllerTest { .request() .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.entity(new ChangePhoneNumberRequest(number, code, null, - Map.of(1L, new DeviceUpdate( - new IncomingMessage(1, null, 1, 1, "foo"), - null, - null))), + List.of(new IncomingMessage(1, null, 1, 1, "foo")), null), MediaType.APPLICATION_JSON_TYPE)); - assertThat(response.getStatus()).isEqualTo(409); - verify(changeNumberManager, never()).changeNumber(any(), any(), any()); + assertThat(response.getStatus()).isEqualTo(400); + verify(changeNumberManager, never()).changeNumber(any(), any(), any(), any()); } @Test @@ -1521,19 +1517,14 @@ class AccountControllerTest { .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.entity(new ChangePhoneNumberRequest( number, code, null, - Map.of( - 2L, new DeviceUpdate( - new IncomingMessage(1, null, 2, 1, "foo"), - null, - null), - 4L, new DeviceUpdate( - new IncomingMessage(1, null, 4, 1, "foo"), - null, - null))), + List.of( + new IncomingMessage(1, null, 2, 1, "foo"), + new IncomingMessage(1, null, 4, 1, "foo")), + Map.of(1L, new SignedPreKey(), 2L, new SignedPreKey(), 3L, new SignedPreKey())), MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(409); - verify(changeNumberManager, never()).changeNumber(any(), any(), any()); + verify(changeNumberManager, never()).changeNumber(any(), any(), any(), any()); } @Test @@ -1555,19 +1546,10 @@ class AccountControllerTest { when(pendingAccountsManager.getCodeForNumber(number)).thenReturn(Optional.of( new StoredVerificationCode(code, System.currentTimeMillis(), "push", null))); - Map perDevice = Map.of( - 1L, new DeviceUpdate( - null, - new SignedPreKey(), - null), - 2L, new DeviceUpdate( + var deviceMessages = List.of( new IncomingMessage(1, null, 2, 2, "content2"), - new SignedPreKey(), - null), - 3L, new DeviceUpdate( - new IncomingMessage(1, null, 3, 3, "content3"), - new SignedPreKey(), - null)); + new IncomingMessage(1, null, 3, 3, "content3")); + var deviceKeys = Map.of(1L, new SignedPreKey(), 2L, new SignedPreKey(), 3L, new SignedPreKey()); final AccountIdentityResponse accountIdentityResponse = resources.getJerseyTest() @@ -1575,10 +1557,12 @@ class AccountControllerTest { .request() .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.entity(new ChangePhoneNumberRequest( - number, code, null, perDevice), + number, code, null, + deviceMessages, + deviceKeys), MediaType.APPLICATION_JSON_TYPE), AccountIdentityResponse.class); - verify(changeNumberManager).changeNumber(eq(AuthHelper.VALID_ACCOUNT), eq(number), any()); + verify(changeNumberManager).changeNumber(eq(AuthHelper.VALID_ACCOUNT), eq(number), any(), any()); assertThat(accountIdentityResponse.getUuid()).isEqualTo(AuthHelper.VALID_UUID); assertThat(accountIdentityResponse.getNumber()).isEqualTo(number); @@ -1604,27 +1588,17 @@ class AccountControllerTest { when(pendingAccountsManager.getCodeForNumber(number)).thenReturn(Optional.of( new StoredVerificationCode(code, System.currentTimeMillis(), "push", null))); - Map perDevice = Map.of( - 1L, new DeviceUpdate( - null, - new SignedPreKey(), - null), - 2L, new DeviceUpdate( - new IncomingMessage(1, null, 2, 1, "foo"), - new SignedPreKey(), - null), - 3L, new DeviceUpdate( - new IncomingMessage(1, null, 3, 1, "foo"), - new SignedPreKey(), - null)); - final Response response = resources.getJerseyTest() .target("/v1/accounts/number") .request() .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.entity(new ChangePhoneNumberRequest( - number, code, null, perDevice), + number, code, null, + List.of( + new IncomingMessage(1, null, 2, 1, "foo"), + new IncomingMessage(1, null, 3, 1, "foo")), + Map.of(1L, new SignedPreKey(), 2L, new SignedPreKey(), 3L, new SignedPreKey())), MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(410);