Refresh accounts before returning device lists

This commit is contained in:
Jon Chambers 2024-12-05 14:35:18 -05:00 committed by GitHub
parent 651e444875
commit 4988b4e0f5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 39 additions and 6 deletions

View File

@ -68,7 +68,6 @@ import org.whispersystems.textsecuregcm.entities.RemoteAttachment;
import org.whispersystems.textsecuregcm.entities.RemoteAttachmentError;
import org.whispersystems.textsecuregcm.entities.RestoreAccountRequest;
import org.whispersystems.textsecuregcm.entities.SetPublicKeyRequest;
import org.whispersystems.textsecuregcm.entities.TransferArchiveResult;
import org.whispersystems.textsecuregcm.entities.TransferArchiveUploadedRequest;
import org.whispersystems.textsecuregcm.identity.IdentityType;
import org.whispersystems.textsecuregcm.limits.RateLimitedByIp;
@ -143,9 +142,13 @@ public class DeviceController {
@GET
@Produces(MediaType.APPLICATION_JSON)
public DeviceInfoList getDevices(@ReadOnly @Auth AuthenticatedDevice auth) {
return new DeviceInfoList(auth.getAccount().getDevices().stream()
.map(DeviceInfo::forDevice)
.toList());
// Devices may change their own names (and primary devices may change the names of linked devices) and so the device
// state associated with the authenticated account may be stale. Fetch a fresh copy to compensate.
return accounts.getByAccountIdentifier(auth.getAccount().getIdentifier(IdentityType.ACI))
.map(account -> new DeviceInfoList(account.getDevices().stream()
.map(DeviceInfo::forDevice)
.toList()))
.orElseThrow(ForbiddenException::new);
}
@DELETE

View File

@ -66,6 +66,7 @@ import org.whispersystems.textsecuregcm.entities.AccountAttributes;
import org.whispersystems.textsecuregcm.entities.ApnRegistrationId;
import org.whispersystems.textsecuregcm.entities.DeviceActivationRequest;
import org.whispersystems.textsecuregcm.entities.DeviceInfo;
import org.whispersystems.textsecuregcm.entities.DeviceInfoList;
import org.whispersystems.textsecuregcm.entities.ECSignedPreKey;
import org.whispersystems.textsecuregcm.entities.GcmRegistrationId;
import org.whispersystems.textsecuregcm.entities.KEMSignedPreKey;
@ -81,7 +82,6 @@ import org.whispersystems.textsecuregcm.limits.RateLimiter;
import org.whispersystems.textsecuregcm.limits.RateLimiters;
import org.whispersystems.textsecuregcm.mappers.DeviceLimitExceededExceptionMapper;
import org.whispersystems.textsecuregcm.mappers.RateLimitExceededExceptionMapper;
import org.whispersystems.textsecuregcm.push.WebSocketConnectionEventManager;
import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.ClientPublicKeysManager;
@ -113,7 +113,6 @@ class DeviceControllerTest {
private static final Account maxedAccount = mock(Account.class);
private static final Device primaryDevice = mock(Device.class);
private static final DisconnectionRequestManager disconnectionRequestManager = mock(DisconnectionRequestManager.class);
private static final WebSocketConnectionEventManager webSocketConnectionEventManager = mock(WebSocketConnectionEventManager.class);
private static final Map<String, Integer> deviceConfiguration = new HashMap<>();
private static final TestClock testClock = TestClock.now();
@ -180,6 +179,37 @@ class DeviceControllerTest {
testClock.unpin();
}
@Test
void getDevices() {
final byte deviceId = Device.PRIMARY_ID;
final byte[] deviceName = "refreshed-device-name".getBytes(StandardCharsets.UTF_8);
final long deviceCreated = System.currentTimeMillis();
final long deviceLastSeen = deviceCreated + 1;
final Device refreshedDevice = mock(Device.class);
when(refreshedDevice.getId()).thenReturn(deviceId);
when(refreshedDevice.getName()).thenReturn(deviceName);
when(refreshedDevice.getCreated()).thenReturn(deviceCreated);
when(refreshedDevice.getLastSeen()).thenReturn(deviceLastSeen);
final Account refreshedAccount = mock(Account.class);
when(refreshedAccount.getDevices()).thenReturn(List.of(refreshedDevice));
when(accountsManager.getByAccountIdentifier(AuthHelper.VALID_UUID)).thenReturn(Optional.of(refreshedAccount));
final DeviceInfoList deviceInfoList = resources.getJerseyTest()
.target("/v1/devices")
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
.get(DeviceInfoList.class);
assertEquals(1, deviceInfoList.devices().size());
assertEquals(deviceId, deviceInfoList.devices().getFirst().id());
assertArrayEquals(deviceName, deviceInfoList.devices().getFirst().name());
assertEquals(deviceCreated, deviceInfoList.devices().getFirst().created());
assertEquals(deviceLastSeen, deviceInfoList.devices().getFirst().lastSeen());
}
@ParameterizedTest
@MethodSource
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")