diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DeviceController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DeviceController.java index 50b08e2d4..4dd141e8f 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DeviceController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DeviceController.java @@ -239,6 +239,8 @@ public class DeviceController { private boolean isCapabilityDowngrade(Account account, DeviceCapabilities capabilities, String userAgent) { boolean isDowngrade = false; + // TODO stories capability + // isDowngrade |= account.isStoriesSupported() && !capabilities.isStories(); isDowngrade |= account.isPniSupported() && !capabilities.isPni(); isDowngrade |= account.isChangeNumberSupported() && !capabilities.isChangeNumber(); isDowngrade |= account.isAnnouncementGroupSupported() && !capabilities.isAnnouncementGroup(); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/entities/UserCapabilities.java b/service/src/main/java/org/whispersystems/textsecuregcm/entities/UserCapabilities.java index c07ef023a..915db323e 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/entities/UserCapabilities.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/entities/UserCapabilities.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2020 Signal Messenger, LLC + * Copyright 2013-2022 Signal Messenger, LLC * SPDX-License-Identifier: AGPL-3.0-only */ @@ -16,7 +16,8 @@ public class UserCapabilities { account.isGv1MigrationSupported(), account.isSenderKeySupported(), account.isAnnouncementGroupSupported(), - account.isChangeNumberSupported()); + account.isChangeNumberSupported(), + account.isStoriesSupported()); } @JsonProperty @@ -34,19 +35,25 @@ public class UserCapabilities { @JsonProperty private boolean changeNumber; - public UserCapabilities() {} + @JsonProperty + private boolean stories; + + public UserCapabilities() { + } public UserCapabilities(final boolean gv2, boolean gv1Migration, final boolean senderKey, final boolean announcementGroup, - final boolean changeNumber) { + final boolean changeNumber, + final boolean stories) { - this.gv2 = gv2; + this.gv2 = gv2; this.gv1Migration = gv1Migration; this.senderKey = senderKey; this.announcementGroup = announcementGroup; this.changeNumber = changeNumber; + this.stories = stories; } public boolean isGv2() { @@ -68,4 +75,8 @@ public class UserCapabilities { public boolean isChangeNumber() { return changeNumber; } + + public boolean isStories() { + return stories; + } } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/storage/Account.java b/service/src/main/java/org/whispersystems/textsecuregcm/storage/Account.java index fc4117fc7..b893da47c 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/Account.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/Account.java @@ -242,6 +242,16 @@ public class Account { .allMatch(device -> device.getCapabilities() != null && device.getCapabilities().isPni()); } + public boolean isStoriesSupported() { + requireNotStale(); + + return devices.stream() + .filter(Device::isEnabled) + // TODO stories capability + // .allMatch(device -> device.getCapabilities() != null && device.getCapabilities().isStories()); + .anyMatch(device -> device.getCapabilities() != null && device.getCapabilities().isStories()); + } + public boolean isEnabled() { requireNotStale(); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/storage/Device.java b/service/src/main/java/org/whispersystems/textsecuregcm/storage/Device.java index 9fc88bdd6..4b6018a41 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/Device.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/Device.java @@ -188,7 +188,7 @@ public class Device { return (id == MASTER_ID && hasChannel && signedPreKey != null) || (id != MASTER_ID && hasChannel && signedPreKey != null && lastSeen > (System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30))); } - + public boolean getFetchesMessages() { return fetchesMessages; } @@ -295,12 +295,15 @@ public class Device { @JsonProperty private boolean pni; + @JsonProperty + private boolean stories; + public DeviceCapabilities() { } public DeviceCapabilities(boolean gv2, final boolean gv2_2, final boolean gv2_3, boolean storage, boolean transfer, boolean gv1Migration, final boolean senderKey, final boolean announcementGroup, final boolean changeNumber, - final boolean pni) { + final boolean pni, final boolean stories) { this.gv2 = gv2; this.gv2_2 = gv2_2; this.gv2_3 = gv2_3; @@ -311,6 +314,7 @@ public class Device { this.announcementGroup = announcementGroup; this.changeNumber = changeNumber; this.pni = pni; + this.stories = stories; } public boolean isGv2() { @@ -352,5 +356,9 @@ public class Device { public boolean isPni() { return pni; } + + public boolean isStories() { + return stories; + } } } diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/MessageControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/MessageControllerTest.java index 1f355f908..39364b74f 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/MessageControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/MessageControllerTest.java @@ -134,22 +134,22 @@ class MessageControllerTest { add(new Device(1, null, "foo", "bar", "isgcm", null, null, false, 111, new SignedPreKey(333, "baz", "boop"), System.currentTimeMillis(), System.currentTimeMillis(), "Test", 0, new Device.DeviceCapabilities(true, false, false, true, true, false, - false, false, false, false))); + false, false, false, false, false))); }}; Set multiDeviceList = new HashSet<>() {{ add(new Device(1, null, "foo", "bar", "isgcm", null, null, false, 222, new SignedPreKey(111, "foo", "bar"), System.currentTimeMillis(), System.currentTimeMillis(), "Test", 0, new Device.DeviceCapabilities(true, false, false, true, false, false, - false, false, false, false))); + false, false, false, false, false))); add(new Device(2, null, "foo", "bar", "isgcm", null, null, false, 333, new SignedPreKey(222, "oof", "rab"), System.currentTimeMillis(), System.currentTimeMillis(), "Test", 0, new Device.DeviceCapabilities(true, false, false, true, false, false, - false, false, false, false))); + false, false, false, false, false))); add(new Device(3, null, "foo", "bar", "isgcm", null, null, false, 444, null, System.currentTimeMillis() - TimeUnit.DAYS.toMillis(31), System.currentTimeMillis(), "Test", 0, new Device.DeviceCapabilities(false, false, false, false, false, false, - false, false, false, false))); + false, false, false, false, false))); }}; Account singleDeviceAccount = new Account(SINGLE_DEVICE_RECIPIENT, SINGLE_DEVICE_UUID, SINGLE_DEVICE_PNI, singleDeviceList, "1234".getBytes()); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsManagerConcurrentModificationIntegrationTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsManagerConcurrentModificationIntegrationTest.java index feb8d3ca3..b8e8cd6bf 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsManagerConcurrentModificationIntegrationTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsManagerConcurrentModificationIntegrationTest.java @@ -183,7 +183,7 @@ class AccountsManagerConcurrentModificationIntegrationTest { "testUserAgent-" + random.nextInt(), 0, new Device.DeviceCapabilities(random.nextBoolean(), random.nextBoolean(), random.nextBoolean(), random.nextBoolean(), random.nextBoolean(), random.nextBoolean(), random.nextBoolean(), - random.nextBoolean(), random.nextBoolean(), random.nextBoolean()))); + random.nextBoolean(), random.nextBoolean(), random.nextBoolean(), random.nextBoolean()))); }); uuid = account.getUuid(); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsManagerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsManagerTest.java index 4726639c4..1fa2d96b3 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsManagerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsManagerTest.java @@ -579,7 +579,7 @@ class AccountsManagerTest { @ValueSource(booleans = {true, false}) void testCreateWithStorageCapability(final boolean hasStorage) throws InterruptedException { final AccountAttributes attributes = new AccountAttributes(false, 0, null, null, true, - new DeviceCapabilities(false, false, false, hasStorage, false, false, false, false, false, false)); + new DeviceCapabilities(false, false, false, hasStorage, false, false, false, false, false, false, false)); final Account account = accountsManager.create("+18005550123", "password", null, attributes, new ArrayList<>()); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsTest.java index 9d3457b45..998ac1293 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsTest.java @@ -840,7 +840,8 @@ class AccountsTest { "testUserAgent-" + random.nextInt(), 0, new Device.DeviceCapabilities(random.nextBoolean(), random.nextBoolean(), random.nextBoolean(), random.nextBoolean(), random.nextBoolean(), random.nextBoolean(), - random.nextBoolean(), random.nextBoolean(), random.nextBoolean(), random.nextBoolean())); + random.nextBoolean(), random.nextBoolean(), random.nextBoolean(), random.nextBoolean(), + random.nextBoolean())); } private Account generateAccount(String number, UUID uuid, final UUID pni) { 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 50769140e..031add05e 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/storage/DeviceTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/storage/DeviceTest.java @@ -72,7 +72,7 @@ class DeviceTest { final boolean gv2_2Capability, final boolean gv2_3Capability, final boolean expectGv2Supported) { final Device.DeviceCapabilities capabilities = new Device.DeviceCapabilities(gv2Capability, gv2_2Capability, gv2_3Capability, false, false, false, - false, false, false, false); + false, false, false, false, false); final Device device = new Device(master ? 1 : 2, "test", "auth-token", "salt", null, apnId, null, false, 1, null, 0, 0, "user-agent", 0, capabilities); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/DeviceControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/DeviceControllerTest.java index a1e7caa92..78108ebb8 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/DeviceControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/DeviceControllerTest.java @@ -305,7 +305,7 @@ class DeviceControllerTest { void deviceDowngradeCapabilitiesTest(final String userAgent, final boolean gv2, final boolean gv2_2, final boolean gv2_3, final int expectedStatus) { DeviceCapabilities deviceCapabilities = new DeviceCapabilities(gv2, gv2_2, gv2_3, true, false, true, true, true, - true, true); + true, true, true); AccountAttributes accountAttributes = new AccountAttributes(false, 1234, null, null, true, deviceCapabilities); Response response = resources.getJerseyTest() .target("/v1/devices/5678901") @@ -346,7 +346,7 @@ class DeviceControllerTest { @Test void deviceDowngradeGv1MigrationTest() { DeviceCapabilities deviceCapabilities = new DeviceCapabilities(true, true, true, true, false, false, true, true, - true, true); + true, true, true); AccountAttributes accountAttributes = new AccountAttributes(false, 1234, null, null, true, deviceCapabilities); Response response = resources.getJerseyTest() .target("/v1/devices/5678901") @@ -357,7 +357,7 @@ class DeviceControllerTest { assertThat(response.getStatus()).isEqualTo(409); - deviceCapabilities = new DeviceCapabilities(true, true, true, true, false, true, true, true, true, true); + deviceCapabilities = new DeviceCapabilities(true, true, true, true, false, true, true, true, true, true, true); accountAttributes = new AccountAttributes(false, 1234, null, null, true, deviceCapabilities); response = resources.getJerseyTest() .target("/v1/devices/5678901") @@ -372,7 +372,7 @@ class DeviceControllerTest { @Test void deviceDowngradeSenderKeyTest() { DeviceCapabilities deviceCapabilities = new DeviceCapabilities(true, true, true, true, true, true, false, true, - true, true); + true, true, true); AccountAttributes accountAttributes = new AccountAttributes(false, 1234, null, null, true, deviceCapabilities); Response response = resources @@ -384,7 +384,7 @@ class DeviceControllerTest { .put(Entity.entity(accountAttributes, MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(409); - deviceCapabilities = new DeviceCapabilities(true, true, true, true, true, true, true, true, true, true); + deviceCapabilities = new DeviceCapabilities(true, true, true, true, true, true, true, true, true, true, true); accountAttributes = new AccountAttributes(false, 1234, null, null, true, deviceCapabilities); response = resources .getJerseyTest() @@ -399,7 +399,7 @@ class DeviceControllerTest { @Test void deviceDowngradeAnnouncementGroupTest() { DeviceCapabilities deviceCapabilities = new DeviceCapabilities(true, true, true, true, true, true, true, false, - true, true); + true, true, true); AccountAttributes accountAttributes = new AccountAttributes(false, 1234, null, null, true, deviceCapabilities); Response response = resources @@ -411,7 +411,7 @@ class DeviceControllerTest { .put(Entity.entity(accountAttributes, MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(409); - deviceCapabilities = new DeviceCapabilities(true, true, true, true, true, true, true, true, true, true); + deviceCapabilities = new DeviceCapabilities(true, true, true, true, true, true, true, true, true, true, true); accountAttributes = new AccountAttributes(false, 1234, null, null, true, deviceCapabilities); response = resources .getJerseyTest() @@ -425,7 +425,8 @@ class DeviceControllerTest { @Test void deviceDowngradeChangeNumberTest() { - DeviceCapabilities deviceCapabilities = new DeviceCapabilities(true, true, true, true, true, true, true, true, false, true); + DeviceCapabilities deviceCapabilities = new DeviceCapabilities(true, true, true, true, true, true, true, true, + false, true, true); AccountAttributes accountAttributes = new AccountAttributes(false, 1234, null, null, true, deviceCapabilities); Response response = resources @@ -438,7 +439,7 @@ class DeviceControllerTest { .put(Entity.entity(accountAttributes, MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(409); - deviceCapabilities = new DeviceCapabilities(true, true, true, true, true, true, true, true, true, true); + deviceCapabilities = new DeviceCapabilities(true, true, true, true, true, true, true, true, true, true, true); accountAttributes = new AccountAttributes(false, 1234, null, null, true, deviceCapabilities); response = resources .getJerseyTest() @@ -454,7 +455,7 @@ class DeviceControllerTest { @Test void deviceDowngradePniTest() { DeviceCapabilities deviceCapabilities = new DeviceCapabilities(true, true, true, true, true, true, true, true, true, - false); + false, true); AccountAttributes accountAttributes = new AccountAttributes(false, 1234, null, null, true, deviceCapabilities); Response response = resources @@ -466,13 +467,45 @@ class DeviceControllerTest { .put(Entity.entity(accountAttributes, MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(409); - deviceCapabilities = new DeviceCapabilities(true, true, true, true, true, true, true, true, true, true); + deviceCapabilities = new DeviceCapabilities(true, true, true, true, true, true, true, true, true, true, true); accountAttributes = new AccountAttributes(false, 1234, null, null, true, deviceCapabilities); response = resources .getJerseyTest() .target("/v1/devices/5678901") .request() - .header("Authorization", AuthHelper.getProvisioningAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", + AuthHelper.getProvisioningAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("User-Agent", "Signal-Android/5.42.8675309 Android/30") + .put(Entity.entity(accountAttributes, MediaType.APPLICATION_JSON_TYPE)); + assertThat(response.getStatus()).isEqualTo(200); + } + + @Test + void deviceDowngradeStoriesTest() { + DeviceCapabilities deviceCapabilities = new DeviceCapabilities(true, true, true, true, true, true, true, true, true, + true, false); + AccountAttributes accountAttributes = + new AccountAttributes(false, 1234, null, null, true, deviceCapabilities); + Response response = resources + .getJerseyTest() + .target("/v1/devices/5678901") + .request() + .header("Authorization", + AuthHelper.getProvisioningAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("User-Agent", "Signal-Android/5.42.8675309 Android/30") + .put(Entity.entity(accountAttributes, MediaType.APPLICATION_JSON_TYPE)); + assertThat(response.getStatus()).isEqualTo(200); // Downgrade is currently supported + // TODO stories capability + // assertThat(response.getStatus()).isEqualTo(409); + + deviceCapabilities = new DeviceCapabilities(true, true, true, true, true, true, true, true, true, true, true); + accountAttributes = new AccountAttributes(false, 1234, null, null, true, deviceCapabilities); + response = resources + .getJerseyTest() + .target("/v1/devices/5678901") + .request() + .header("Authorization", + AuthHelper.getProvisioningAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("User-Agent", "Signal-Android/5.42.8675309 Android/30") .put(Entity.entity(accountAttributes, MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(200); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/AccountTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/AccountTest.java index a4a4edbb0..6f8bb38ff 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/AccountTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/AccountTest.java @@ -62,6 +62,10 @@ class AccountTest { private final Device pniIncapableDevice = mock(Device.class); private final Device pniIncapableExpiredDevice = mock(Device.class); + private final Device storiesCapableDevice = mock(Device.class); + private final Device storiesIncapableDevice = mock(Device.class); + private final Device storiesIncapableExpiredDevice = mock(Device.class); + @BeforeEach void setup() { when(oldMasterDevice.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(366)); @@ -97,64 +101,76 @@ class AccountTest { when(gv2IncapableExpiredDevice.isEnabled()).thenReturn(false); when(gv1MigrationCapableDevice.getCapabilities()).thenReturn( - new DeviceCapabilities(true, true, true, true, true, true, false, false, false, false)); + new DeviceCapabilities(true, true, true, true, true, true, false, false, false, false, false)); when(gv1MigrationCapableDevice.isEnabled()).thenReturn(true); when(gv1MigrationIncapableDevice.getCapabilities()).thenReturn( - new DeviceCapabilities(true, true, true, true, true, false, false, false, false, false)); + new DeviceCapabilities(true, true, true, true, true, false, false, false, false, false, false)); when(gv1MigrationIncapableDevice.isEnabled()).thenReturn(true); when(gv1MigrationIncapableExpiredDevice.getCapabilities()).thenReturn( - new DeviceCapabilities(true, true, true, true, true, false, false, false, false, false)); + new DeviceCapabilities(true, true, true, true, true, false, false, false, false, false, false)); when(gv1MigrationIncapableExpiredDevice.isEnabled()).thenReturn(false); when(senderKeyCapableDevice.getCapabilities()).thenReturn( - new DeviceCapabilities(true, true, true, true, true, true, true, false, false, false)); + new DeviceCapabilities(true, true, true, true, true, true, true, false, false, false, false)); when(senderKeyCapableDevice.isEnabled()).thenReturn(true); when(senderKeyIncapableDevice.getCapabilities()).thenReturn( - new DeviceCapabilities(true, true, true, true, true, true, false, false, false, false)); + new DeviceCapabilities(true, true, true, true, true, true, false, false, false, false, false)); when(senderKeyIncapableDevice.isEnabled()).thenReturn(true); when(senderKeyIncapableExpiredDevice.getCapabilities()).thenReturn( - new DeviceCapabilities(true, true, true, true, true, true, false, false, false, false)); + new DeviceCapabilities(true, true, true, true, true, true, false, false, false, false, false)); when(senderKeyIncapableExpiredDevice.isEnabled()).thenReturn(false); when(announcementGroupCapableDevice.getCapabilities()).thenReturn( - new DeviceCapabilities(true, true, true, true, true, true, true, true, false, false)); + new DeviceCapabilities(true, true, true, true, true, true, true, true, false, false, false)); when(announcementGroupCapableDevice.isEnabled()).thenReturn(true); when(announcementGroupIncapableDevice.getCapabilities()).thenReturn( - new DeviceCapabilities(true, true, true, true, true, true, true, false, false, false)); + new DeviceCapabilities(true, true, true, true, true, true, true, false, false, false, false)); when(announcementGroupIncapableDevice.isEnabled()).thenReturn(true); when(announcementGroupIncapableExpiredDevice.getCapabilities()).thenReturn( - new DeviceCapabilities(true, true, true, true, true, true, true, false, false, false)); + new DeviceCapabilities(true, true, true, true, true, true, true, false, false, false, false)); when(announcementGroupIncapableExpiredDevice.isEnabled()).thenReturn(false); when(changeNumberCapableDevice.getCapabilities()).thenReturn( - new DeviceCapabilities(true, true, true, true, true, true, true, false, true, false)); + new DeviceCapabilities(true, true, true, true, true, true, true, false, true, false, false)); when(changeNumberCapableDevice.isEnabled()).thenReturn(true); when(changeNumberIncapableDevice.getCapabilities()).thenReturn( - new DeviceCapabilities(true, true, true, true, true, true, true, false, false, false)); + new DeviceCapabilities(true, true, true, true, true, true, true, false, false, false, false)); when(changeNumberIncapableDevice.isEnabled()).thenReturn(true); when(changeNumberIncapableExpiredDevice.getCapabilities()).thenReturn( - new DeviceCapabilities(true, true, true, true, true, true, true, false, false, false)); + new DeviceCapabilities(true, true, true, true, true, true, true, false, false, false, false)); when(changeNumberIncapableExpiredDevice.isEnabled()).thenReturn(false); when(pniCapableDevice.getCapabilities()).thenReturn( - new DeviceCapabilities(true, true, true, true, true, true, true, false, false, true)); + new DeviceCapabilities(true, true, true, true, true, true, true, false, false, true, false)); when(pniCapableDevice.isEnabled()).thenReturn(true); when(pniIncapableDevice.getCapabilities()).thenReturn( - new DeviceCapabilities(true, true, true, true, true, true, true, false, false, false)); + new DeviceCapabilities(true, true, true, true, true, true, true, false, false, false, false)); when(pniIncapableDevice.isEnabled()).thenReturn(true); when(pniIncapableExpiredDevice.getCapabilities()).thenReturn( - new DeviceCapabilities(true, true, true, true, true, true, true, false, false, false)); + new DeviceCapabilities(true, true, true, true, true, true, true, false, false, false, false)); when(pniIncapableExpiredDevice.isEnabled()).thenReturn(false); + + when(storiesCapableDevice.getCapabilities()).thenReturn( + new DeviceCapabilities(true, true, true, true, true, true, true, false, false, false, true)); + when(storiesCapableDevice.isEnabled()).thenReturn(true); + + when(storiesIncapableDevice.getCapabilities()).thenReturn( + new DeviceCapabilities(true, true, true, true, true, true, true, false, false, false, false)); + when(storiesIncapableDevice.isEnabled()).thenReturn(true); + + when(storiesIncapableExpiredDevice.getCapabilities()).thenReturn( + new DeviceCapabilities(true, true, true, true, true, true, true, false, false, false, false)); + when(storiesIncapableExpiredDevice.isEnabled()).thenReturn(false); } @Test @@ -346,9 +362,25 @@ class AccountTest { "1234".getBytes(StandardCharsets.UTF_8)).isPniSupported()).isTrue(); } + @Test + void isStoriesSupported() { + assertThat(new Account("+18005551234", UUID.randomUUID(), + UUID.randomUUID(), Set.of(storiesCapableDevice), + "1234".getBytes(StandardCharsets.UTF_8)).isStoriesSupported()).isTrue(); + assertThat(new Account("+18005551234", UUID.randomUUID(), + UUID.randomUUID(), Set.of(storiesCapableDevice, storiesIncapableDevice), + "1234".getBytes(StandardCharsets.UTF_8)).isStoriesSupported()).isTrue(); + // TODO stories capability + // "1234".getBytes(StandardCharsets.UTF_8)).isStoriesSupported()).isFalse(); + assertThat(new Account("+18005551234", UUID.randomUUID(), + UUID.randomUUID(), Set.of(storiesCapableDevice, storiesIncapableExpiredDevice), + "1234".getBytes(StandardCharsets.UTF_8)).isStoriesSupported()).isTrue(); + } + @Test void stale() { - final Account account = new Account("+14151234567", UUID.randomUUID(), UUID.randomUUID(), Collections.emptySet(), new byte[0]); + final Account account = new Account("+14151234567", UUID.randomUUID(), UUID.randomUUID(), Collections.emptySet(), + new byte[0]); assertDoesNotThrow(account::getNumber); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/util/AccountsHelper.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/util/AccountsHelper.java index 08702280a..4cdeb23b3 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/util/AccountsHelper.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/util/AccountsHelper.java @@ -157,6 +157,10 @@ public class AccountsHelper { when(updatedAccount.isPniSupported()).thenAnswer(stubbing); break; } + case "isStoriesSupported": { + when(updatedAccount.isStoriesSupported()).thenAnswer(stubbing); + break; + } case "getEnabledDeviceCount": { when(updatedAccount.getEnabledDeviceCount()).thenAnswer(stubbing); break;