diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java index 3796d0158..d4610f1eb 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java @@ -5,7 +5,6 @@ import com.codahale.metrics.annotation.Timed; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Hex; -import org.hibernate.validator.constraints.Length; import org.hibernate.validator.valuehandling.UnwrapValidatedValue; import org.signal.zkgroup.InvalidInputException; import org.signal.zkgroup.VerificationFailedException; @@ -30,8 +29,8 @@ import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.ProfilesManager; import org.whispersystems.textsecuregcm.storage.UsernamesManager; -import org.whispersystems.textsecuregcm.util.ExactlySize; import org.whispersystems.textsecuregcm.storage.VersionedProfile; +import org.whispersystems.textsecuregcm.util.ExactlySize; import org.whispersystems.textsecuregcm.util.Pair; import javax.validation.Valid; @@ -199,7 +198,7 @@ public class ProfileController { accountProfile.get().getIdentityKey(), UnidentifiedAccessChecksum.generateFor(accountProfile.get().getUnidentifiedAccessKey()), accountProfile.get().isUnrestrictedUnidentifiedAccess(), - new UserCapabilities(accountProfile.get().isUuidAddressingSupported()), + new UserCapabilities(accountProfile.get().isUuidAddressingSupported(), accountProfile.get().isGroupsV2Supported()), username.orElse(null), null, credential.orElse(null))); } catch (InvalidInputException e) { @@ -235,7 +234,7 @@ public class ProfileController { accountProfile.get().getIdentityKey(), UnidentifiedAccessChecksum.generateFor(accountProfile.get().getUnidentifiedAccessKey()), accountProfile.get().isUnrestrictedUnidentifiedAccess(), - new UserCapabilities(accountProfile.get().isUuidAddressingSupported()), + new UserCapabilities(accountProfile.get().isUuidAddressingSupported(), accountProfile.get().isGroupsV2Supported()), username, accountProfile.get().getUuid(), null); } @@ -306,7 +305,7 @@ public class ProfileController { accountProfile.get().getIdentityKey(), UnidentifiedAccessChecksum.generateFor(accountProfile.get().getUnidentifiedAccessKey()), accountProfile.get().isUnrestrictedUnidentifiedAccess(), - new UserCapabilities(accountProfile.get().isUuidAddressingSupported()), + new UserCapabilities(accountProfile.get().isUuidAddressingSupported(), accountProfile.get().isGroupsV2Supported()), username.orElse(null), null, null); } 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 2510dc6aa..217b8f3e8 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/entities/UserCapabilities.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/entities/UserCapabilities.java @@ -6,13 +6,21 @@ public class UserCapabilities { @JsonProperty private boolean uuid; + @JsonProperty + private boolean gv2; + public UserCapabilities() {} - public UserCapabilities(boolean uuid) { + public UserCapabilities(boolean uuid, boolean gv2) { this.uuid = uuid; + this.gv2 = gv2; } public boolean isUuid() { return uuid; } + + public boolean isGv2() { + return gv2; + } } 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 2a0379184..1881c7d33 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/Account.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/Account.java @@ -138,6 +138,12 @@ public class Account implements Principal { .allMatch(device -> device.getCapabilities() != null && device.getCapabilities().isUuid()); } + public boolean isGroupsV2Supported() { + return devices.stream() + .filter(Device::isEnabled) + .allMatch(device -> device.getCapabilities() != null && device.getCapabilities().isGv2()); + } + public boolean isEnabled() { return getMasterDevice().isPresent() && 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 1941e1cc0..676c005d9 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/Device.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/Device.java @@ -270,15 +270,23 @@ public class Device { @JsonProperty private boolean uuid; + @JsonProperty + private boolean gv2; + public DeviceCapabilities() {} - public DeviceCapabilities(boolean uuid) { + public DeviceCapabilities(boolean uuid, boolean gv2) { this.uuid = uuid; + this.gv2 = gv2; } public boolean isUuid() { return uuid; } + + public boolean isGv2() { + return gv2; + } } } diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java index ccc844550..385865e75 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java @@ -85,13 +85,13 @@ public class MessageControllerTest { @Before public void setup() throws Exception { Set singleDeviceList = new HashSet() {{ - add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 111, new SignedPreKey(333, "baz", "boop"), System.currentTimeMillis(), System.currentTimeMillis(), "Test", 0, new Device.DeviceCapabilities(true))); + add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 111, new SignedPreKey(333, "baz", "boop"), System.currentTimeMillis(), System.currentTimeMillis(), "Test", 0, new Device.DeviceCapabilities(true, true))); }}; Set multiDeviceList = new HashSet() {{ - add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 222, new SignedPreKey(111, "foo", "bar"), System.currentTimeMillis(), System.currentTimeMillis(), "Test", 0, new Device.DeviceCapabilities(true))); - add(new Device(2, null, "foo", "bar", "baz", "isgcm", null, null, false, 333, new SignedPreKey(222, "oof", "rab"), System.currentTimeMillis(), System.currentTimeMillis(), "Test", 0, new Device.DeviceCapabilities(true))); - add(new Device(3, null, "foo", "bar", "baz", "isgcm", null, null, false, 444, null, System.currentTimeMillis() - TimeUnit.DAYS.toMillis(31), System.currentTimeMillis(), "Test", 0, new Device.DeviceCapabilities(false))); + add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 222, new SignedPreKey(111, "foo", "bar"), System.currentTimeMillis(), System.currentTimeMillis(), "Test", 0, new Device.DeviceCapabilities(true, true))); + add(new Device(2, null, "foo", "bar", "baz", "isgcm", null, null, false, 333, new SignedPreKey(222, "oof", "rab"), System.currentTimeMillis(), System.currentTimeMillis(), "Test", 0, new Device.DeviceCapabilities(true, true))); + add(new Device(3, null, "foo", "bar", "baz", "isgcm", null, null, false, 444, null, System.currentTimeMillis() - TimeUnit.DAYS.toMillis(31), System.currentTimeMillis(), "Test", 0, new Device.DeviceCapabilities(false, false))); }}; Account singleDeviceAccount = new Account(SINGLE_DEVICE_RECIPIENT, SINGLE_DEVICE_UUID, singleDeviceList, "1234".getBytes()); 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 04c8e03fb..0647acf40 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 @@ -49,15 +49,15 @@ public class AccountTest { when(oldSecondaryDevice.isEnabled()).thenReturn(false); when(oldSecondaryDevice.getId()).thenReturn(2L); - when(uuidCapableDevice.getCapabilities()).thenReturn(new Device.DeviceCapabilities(true)); + when(uuidCapableDevice.getCapabilities()).thenReturn(new Device.DeviceCapabilities(true, true)); when(uuidCapableDevice.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1)); when(uuidCapableDevice.isEnabled()).thenReturn(true); - when(uuidIncapableDevice.getCapabilities()).thenReturn(new Device.DeviceCapabilities(false)); + when(uuidIncapableDevice.getCapabilities()).thenReturn(new Device.DeviceCapabilities(false, false)); when(uuidIncapableDevice.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1)); when(uuidIncapableDevice.isEnabled()).thenReturn(true); - when(uuidIncapableExpiredDevice.getCapabilities()).thenReturn(new Device.DeviceCapabilities(false)); + when(uuidIncapableExpiredDevice.getCapabilities()).thenReturn(new Device.DeviceCapabilities(false, false)); when(uuidIncapableExpiredDevice.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(31)); when(uuidIncapableExpiredDevice.isEnabled()).thenReturn(false); } diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/AccountsTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/AccountsTest.java index ed11f6686..4e24969a8 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/AccountsTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/AccountsTest.java @@ -270,7 +270,7 @@ public class AccountsTest { private Device generateDevice(long id) { Random random = new Random(System.currentTimeMillis()); SignedPreKey signedPreKey = new SignedPreKey(random.nextInt(), "testPublicKey-" + random.nextInt(), "testSignature-" + random.nextInt()); - return new Device(id, "testName-" + random.nextInt(), "testAuthToken-" + random.nextInt(), "testSalt-" + random.nextInt(), null, "testGcmId-" + random.nextInt(), "testApnId-" + random.nextInt(), "testVoipApnId-" + random.nextInt(), random.nextBoolean(), random.nextInt(), signedPreKey, random.nextInt(), random.nextInt(), "testUserAgent-" + random.nextInt() , 0, new Device.DeviceCapabilities(random.nextBoolean())); + return new Device(id, "testName-" + random.nextInt(), "testAuthToken-" + random.nextInt(), "testSalt-" + random.nextInt(), null, "testGcmId-" + random.nextInt(), "testApnId-" + random.nextInt(), "testVoipApnId-" + random.nextInt(), random.nextBoolean(), random.nextInt(), signedPreKey, random.nextInt(), random.nextInt(), "testUserAgent-" + random.nextInt() , 0, new Device.DeviceCapabilities(random.nextBoolean(), random.nextBoolean())); } private Account generateAccount(String number, UUID uuid) {