Add support for capabilities

This commit is contained in:
Moxie Marlinspike 2019-09-23 12:01:12 -07:00
parent 62a10047ca
commit c623f70caa
12 changed files with 154 additions and 32 deletions

View File

@ -487,7 +487,7 @@ public class AccountController {
device.setFetchesMessages(attributes.getFetchesMessages()); device.setFetchesMessages(attributes.getFetchesMessages());
device.setName(attributes.getName()); device.setName(attributes.getName());
device.setLastSeen(Util.todayInMillis()); device.setLastSeen(Util.todayInMillis());
device.setUnauthenticatedDeliverySupported(attributes.getUnidentifiedAccessKey() != null); device.setCapabilities(attributes.getCapabilities());
device.setRegistrationId(attributes.getRegistrationId()); device.setRegistrationId(attributes.getRegistrationId());
device.setSignalingKey(attributes.getSignalingKey()); device.setSignalingKey(attributes.getSignalingKey());
device.setUserAgent(userAgent); device.setUserAgent(userAgent);
@ -599,7 +599,7 @@ public class AccountController {
device.setFetchesMessages(accountAttributes.getFetchesMessages()); device.setFetchesMessages(accountAttributes.getFetchesMessages());
device.setRegistrationId(accountAttributes.getRegistrationId()); device.setRegistrationId(accountAttributes.getRegistrationId());
device.setName(accountAttributes.getName()); device.setName(accountAttributes.getName());
device.setUnauthenticatedDeliverySupported(accountAttributes.getUnidentifiedAccessKey() != null); device.setCapabilities(accountAttributes.getCapabilities());
device.setCreated(System.currentTimeMillis()); device.setCreated(System.currentTimeMillis());
device.setLastSeen(Util.todayInMillis()); device.setLastSeen(Util.todayInMillis());
device.setUserAgent(userAgent); device.setUserAgent(userAgent);

View File

@ -33,6 +33,7 @@ import org.whispersystems.textsecuregcm.sqs.DirectoryQueue;
import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.Device.DeviceCapabilities;
import org.whispersystems.textsecuregcm.storage.MessagesManager; import org.whispersystems.textsecuregcm.storage.MessagesManager;
import org.whispersystems.textsecuregcm.storage.PendingDevicesManager; import org.whispersystems.textsecuregcm.storage.PendingDevicesManager;
import org.whispersystems.textsecuregcm.util.Util; import org.whispersystems.textsecuregcm.util.Util;
@ -221,7 +222,15 @@ public class DeviceController {
@Path("/unauthenticated_delivery") @Path("/unauthenticated_delivery")
public void setUnauthenticatedDelivery(@Auth Account account) { public void setUnauthenticatedDelivery(@Auth Account account) {
assert(account.getAuthenticatedDevice().isPresent()); assert(account.getAuthenticatedDevice().isPresent());
account.getAuthenticatedDevice().get().setUnauthenticatedDeliverySupported(true); // Deprecated
}
@Timed
@PUT
@Path("/capabilities")
public void setCapabiltities(@Auth Account account, @Valid DeviceCapabilities capabilities) {
assert(account.getAuthenticatedDevice().isPresent());
account.getAuthenticatedDevice().get().setCapabilities(capabilities);
accounts.update(account); accounts.update(account);
} }

View File

@ -17,6 +17,7 @@ import org.whispersystems.textsecuregcm.auth.UnidentifiedAccessChecksum;
import org.whispersystems.textsecuregcm.configuration.CdnConfiguration; import org.whispersystems.textsecuregcm.configuration.CdnConfiguration;
import org.whispersystems.textsecuregcm.entities.Profile; import org.whispersystems.textsecuregcm.entities.Profile;
import org.whispersystems.textsecuregcm.entities.ProfileAvatarUploadAttributes; import org.whispersystems.textsecuregcm.entities.ProfileAvatarUploadAttributes;
import org.whispersystems.textsecuregcm.entities.UserCapabilities;
import org.whispersystems.textsecuregcm.limits.RateLimiters; import org.whispersystems.textsecuregcm.limits.RateLimiters;
import org.whispersystems.textsecuregcm.s3.PolicySigner; import org.whispersystems.textsecuregcm.s3.PolicySigner;
import org.whispersystems.textsecuregcm.s3.PostPolicyGenerator; import org.whispersystems.textsecuregcm.s3.PostPolicyGenerator;
@ -102,8 +103,9 @@ public class ProfileController {
return new Profile(accountProfile.get().getProfileName(), return new Profile(accountProfile.get().getProfileName(),
accountProfile.get().getAvatar(), accountProfile.get().getAvatar(),
accountProfile.get().getIdentityKey(), accountProfile.get().getIdentityKey(),
accountProfile.get().isUnauthenticatedDeliverySupported() ? UnidentifiedAccessChecksum.generateFor(accountProfile.get().getUnidentifiedAccessKey()) : null, UnidentifiedAccessChecksum.generateFor(accountProfile.get().getUnidentifiedAccessKey()),
accountProfile.get().isUnrestrictedUnidentifiedAccess()); accountProfile.get().isUnrestrictedUnidentifiedAccess(),
new UserCapabilities(accountProfile.get().isUuidAddressingSupported()));
} }
@Timed @Timed

View File

@ -19,6 +19,8 @@ package org.whispersystems.textsecuregcm.entities;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.Length;
import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.Device.DeviceCapabilities;
public class AccountAttributes { public class AccountAttributes {
@ -47,6 +49,9 @@ public class AccountAttributes {
@JsonProperty @JsonProperty
private boolean unrestrictedUnidentifiedAccess; private boolean unrestrictedUnidentifiedAccess;
@JsonProperty
private DeviceCapabilities capabilities;
public AccountAttributes() {} public AccountAttributes() {}
@VisibleForTesting @VisibleForTesting
@ -95,4 +100,8 @@ public class AccountAttributes {
public boolean isUnrestrictedUnidentifiedAccess() { public boolean isUnrestrictedUnidentifiedAccess() {
return unrestrictedUnidentifiedAccess; return unrestrictedUnidentifiedAccess;
} }
public DeviceCapabilities getCapabilities() {
return capabilities;
}
} }

View File

@ -3,10 +3,6 @@ package org.whispersystems.textsecuregcm.entities;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.Max;
public class Profile { public class Profile {
@JsonProperty @JsonProperty
@ -24,14 +20,21 @@ public class Profile {
@JsonProperty @JsonProperty
private boolean unrestrictedUnidentifiedAccess; private boolean unrestrictedUnidentifiedAccess;
@JsonProperty
private UserCapabilities capabilities;
public Profile() {} public Profile() {}
public Profile(String name, String avatar, String identityKey, String unidentifiedAccess, boolean unrestrictedUnidentifiedAccess) { public Profile(String name, String avatar, String identityKey,
String unidentifiedAccess, boolean unrestrictedUnidentifiedAccess,
UserCapabilities capabilities)
{
this.name = name; this.name = name;
this.avatar = avatar; this.avatar = avatar;
this.identityKey = identityKey; this.identityKey = identityKey;
this.unidentifiedAccess = unidentifiedAccess; this.unidentifiedAccess = unidentifiedAccess;
this.unrestrictedUnidentifiedAccess = unrestrictedUnidentifiedAccess; this.unrestrictedUnidentifiedAccess = unrestrictedUnidentifiedAccess;
this.capabilities = capabilities;
} }
@VisibleForTesting @VisibleForTesting
@ -59,4 +62,9 @@ public class Profile {
return unrestrictedUnidentifiedAccess; return unrestrictedUnidentifiedAccess;
} }
@VisibleForTesting
public UserCapabilities getCapabilities() {
return capabilities;
}
} }

View File

@ -0,0 +1,18 @@
package org.whispersystems.textsecuregcm.entities;
import com.fasterxml.jackson.annotation.JsonProperty;
public class UserCapabilities {
@JsonProperty
private boolean uuid;
public UserCapabilities() {}
public UserCapabilities(boolean uuid) {
this.uuid = uuid;
}
public boolean isUuid() {
return uuid;
}
}

View File

@ -20,7 +20,6 @@ package org.whispersystems.textsecuregcm.storage;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import org.whispersystems.textsecuregcm.auth.AmbiguousIdentifier; import org.whispersystems.textsecuregcm.auth.AmbiguousIdentifier;
import javax.security.auth.Subject; import javax.security.auth.Subject;
@ -33,8 +32,6 @@ import java.util.concurrent.TimeUnit;
public class Account implements Principal { public class Account implements Principal {
static final int MEMCACHE_VERION = 5;
@JsonIgnore @JsonIgnore
private UUID uuid; private UUID uuid;
@ -114,7 +111,7 @@ public class Account implements Principal {
} }
public void removeDevice(long deviceId) { public void removeDevice(long deviceId) {
this.devices.remove(new Device(deviceId, null, null, null, null, null, null, null, false, 0, null, 0, 0, "NA", false, 0)); this.devices.remove(new Device(deviceId, null, null, null, null, null, null, null, false, 0, null, 0, 0, "NA", 0, null));
} }
public Set<Device> getDevices() { public Set<Device> getDevices() {
@ -135,8 +132,8 @@ public class Account implements Principal {
return Optional.empty(); return Optional.empty();
} }
public boolean isUnauthenticatedDeliverySupported() { public boolean isUuidAddressingSupported() {
return devices.stream().filter(Device::isEnabled).allMatch(Device::isUnauthenticatedDeliverySupported); return devices.stream().filter(Device::isEnabled).allMatch(device -> device.getCapabilities().isUuid());
} }
public boolean isEnabled() { public boolean isEnabled() {

View File

@ -19,6 +19,7 @@ package org.whispersystems.textsecuregcm.storage;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials; import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials;
import org.whispersystems.textsecuregcm.entities.UserCapabilities;
import org.whispersystems.textsecuregcm.entities.SignedPreKey; import org.whispersystems.textsecuregcm.entities.SignedPreKey;
import org.whispersystems.textsecuregcm.util.Util; import org.whispersystems.textsecuregcm.util.Util;
@ -77,7 +78,7 @@ public class Device {
private String userAgent; private String userAgent;
@JsonProperty @JsonProperty
private boolean unauthenticatedDelivery; private DeviceCapabilities capabilities;
public Device() {} public Device() {}
@ -86,7 +87,7 @@ public class Device {
String voipApnId, boolean fetchesMessages, String voipApnId, boolean fetchesMessages,
int registrationId, SignedPreKey signedPreKey, int registrationId, SignedPreKey signedPreKey,
long lastSeen, long created, String userAgent, long lastSeen, long created, String userAgent,
boolean unauthenticatedDelivery, long uninstalledFeedback) long uninstalledFeedback, DeviceCapabilities capabilities)
{ {
this.id = id; this.id = id;
this.name = name; this.name = name;
@ -102,8 +103,8 @@ public class Device {
this.lastSeen = lastSeen; this.lastSeen = lastSeen;
this.created = created; this.created = created;
this.userAgent = userAgent; this.userAgent = userAgent;
this.unauthenticatedDelivery = unauthenticatedDelivery;
this.uninstalledFeedback = uninstalledFeedback; this.uninstalledFeedback = uninstalledFeedback;
this.capabilities = capabilities;
} }
public String getApnId() { public String getApnId() {
@ -178,14 +179,6 @@ public class Device {
this.name = name; this.name = name;
} }
public boolean isUnauthenticatedDeliverySupported() {
return unauthenticatedDelivery;
}
public void setUnauthenticatedDeliverySupported(boolean unauthenticatedDelivery) {
this.unauthenticatedDelivery = unauthenticatedDelivery;
}
public void setAuthenticationCredentials(AuthenticationCredentials credentials) { public void setAuthenticationCredentials(AuthenticationCredentials credentials) {
this.authToken = credentials.getHashedAuthenticationToken(); this.authToken = credentials.getHashedAuthenticationToken();
this.salt = credentials.getSalt(); this.salt = credentials.getSalt();
@ -195,6 +188,14 @@ public class Device {
return new AuthenticationCredentials(authToken, salt); return new AuthenticationCredentials(authToken, salt);
} }
public DeviceCapabilities getCapabilities() {
return capabilities;
}
public void setCapabilities(DeviceCapabilities capabilities) {
this.capabilities = capabilities;
}
public String getSignalingKey() { public String getSignalingKey() {
return signalingKey; return signalingKey;
} }
@ -262,4 +263,20 @@ public class Device {
public int hashCode() { public int hashCode() {
return (int)this.id; return (int)this.id;
} }
public static class DeviceCapabilities {
@JsonProperty
private boolean uuid;
public DeviceCapabilities() {}
public DeviceCapabilities(boolean uuid) {
this.uuid = uuid;
}
public boolean isUuid() {
return uuid;
}
}
} }

View File

@ -85,13 +85,13 @@ public class MessageControllerTest {
@Before @Before
public void setup() throws Exception { public void setup() throws Exception {
Set<Device> singleDeviceList = new HashSet<Device>() {{ Set<Device> singleDeviceList = new HashSet<Device>() {{
add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 111, new SignedPreKey(333, "baz", "boop"), System.currentTimeMillis(), System.currentTimeMillis(), "Test", true, 0)); 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)));
}}; }};
Set<Device> multiDeviceList = new HashSet<Device>() {{ Set<Device> multiDeviceList = new HashSet<Device>() {{
add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 222, new SignedPreKey(111, "foo", "bar"), System.currentTimeMillis(), System.currentTimeMillis(), "Test", true, 0)); 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", true, 0)); 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", true, 0)); 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)));
}}; }};
Account singleDeviceAccount = new Account(SINGLE_DEVICE_RECIPIENT, SINGLE_DEVICE_UUID, singleDeviceList, "1234".getBytes()); Account singleDeviceAccount = new Account(SINGLE_DEVICE_RECIPIENT, SINGLE_DEVICE_UUID, singleDeviceList, "1234".getBytes());

View File

@ -63,9 +63,22 @@ public class ProfileControllerTest {
when(profileAccount.getAvatar()).thenReturn("profiles/bang"); when(profileAccount.getAvatar()).thenReturn("profiles/bang");
when(profileAccount.getAvatarDigest()).thenReturn("buh"); when(profileAccount.getAvatarDigest()).thenReturn("buh");
when(profileAccount.isEnabled()).thenReturn(true); when(profileAccount.isEnabled()).thenReturn(true);
when(profileAccount.isUuidAddressingSupported()).thenReturn(false);
Account capabilitiesAccount = mock(Account.class);
when(capabilitiesAccount.getIdentityKey()).thenReturn("barz");
when(capabilitiesAccount.getProfileName()).thenReturn("bazz");
when(capabilitiesAccount.getAvatar()).thenReturn("profiles/bangz");
when(capabilitiesAccount.getAvatarDigest()).thenReturn("buz");
when(capabilitiesAccount.isEnabled()).thenReturn(true);
when(capabilitiesAccount.isUuidAddressingSupported()).thenReturn(true);
when(accountsManager.get(AuthHelper.VALID_NUMBER_TWO)).thenReturn(Optional.of(profileAccount)); when(accountsManager.get(AuthHelper.VALID_NUMBER_TWO)).thenReturn(Optional.of(profileAccount));
when(accountsManager.get(argThat((ArgumentMatcher<AmbiguousIdentifier>) identifier -> identifier != null && identifier.hasNumber() && identifier.getNumber().equals(AuthHelper.VALID_NUMBER_TWO)))).thenReturn(Optional.of(profileAccount)); when(accountsManager.get(argThat((ArgumentMatcher<AmbiguousIdentifier>) identifier -> identifier != null && identifier.hasNumber() && identifier.getNumber().equals(AuthHelper.VALID_NUMBER_TWO)))).thenReturn(Optional.of(profileAccount));
when(accountsManager.get(AuthHelper.VALID_NUMBER)).thenReturn(Optional.of(capabilitiesAccount));
when(accountsManager.get(argThat((ArgumentMatcher<AmbiguousIdentifier>) identifier -> identifier != null && identifier.hasNumber() && identifier.getNumber().equals(AuthHelper.VALID_NUMBER)))).thenReturn(Optional.of(capabilitiesAccount));
} }
@ -80,6 +93,7 @@ public class ProfileControllerTest {
assertThat(profile.getIdentityKey()).isEqualTo("bar"); assertThat(profile.getIdentityKey()).isEqualTo("bar");
assertThat(profile.getName()).isEqualTo("baz"); assertThat(profile.getName()).isEqualTo("baz");
assertThat(profile.getAvatar()).isEqualTo("profiles/bang"); assertThat(profile.getAvatar()).isEqualTo("profiles/bang");
assertThat(profile.getCapabilities().isUuid()).isFalse();
verify(accountsManager, times(1)).get(argThat((ArgumentMatcher<AmbiguousIdentifier>) identifier -> identifier != null && identifier.hasNumber() && identifier.getNumber().equals(AuthHelper.VALID_NUMBER_TWO))); verify(accountsManager, times(1)).get(argThat((ArgumentMatcher<AmbiguousIdentifier>) identifier -> identifier != null && identifier.hasNumber() && identifier.getNumber().equals(AuthHelper.VALID_NUMBER_TWO)));
verify(rateLimiters, times(1)).getProfileLimiter(); verify(rateLimiters, times(1)).getProfileLimiter();
@ -107,4 +121,15 @@ public class ProfileControllerTest {
assertThat(response.getStatus()).isEqualTo(401); assertThat(response.getStatus()).isEqualTo(401);
} }
@Test
public void testProfileCapabilities() throws Exception {
Profile profile= resources.getJerseyTest()
.target("/v1/profile/" + AuthHelper.VALID_NUMBER)
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(Profile.class);
assertThat(profile.getCapabilities().isUuid()).isTrue();
}
} }

View File

@ -23,6 +23,10 @@ public class AccountTest {
private final Device recentSecondaryDevice = mock(Device.class); private final Device recentSecondaryDevice = mock(Device.class);
private final Device oldSecondaryDevice = mock(Device.class); private final Device oldSecondaryDevice = mock(Device.class);
private final Device uuidCapableDevice = mock(Device.class);
private final Device uuidIncapableDevice = mock(Device.class);
private final Device uuidIncapableExpiredDevice = mock(Device.class);
@Before @Before
public void setup() { public void setup() {
when(oldMasterDevice.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(366)); when(oldMasterDevice.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(366));
@ -44,6 +48,18 @@ public class AccountTest {
when(oldSecondaryDevice.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(366)); when(oldSecondaryDevice.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(366));
when(oldSecondaryDevice.isEnabled()).thenReturn(false); when(oldSecondaryDevice.isEnabled()).thenReturn(false);
when(oldSecondaryDevice.getId()).thenReturn(2L); when(oldSecondaryDevice.getId()).thenReturn(2L);
when(uuidCapableDevice.getCapabilities()).thenReturn(new Device.DeviceCapabilities(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.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1));
when(uuidIncapableDevice.isEnabled()).thenReturn(true);
when(uuidIncapableExpiredDevice.getCapabilities()).thenReturn(new Device.DeviceCapabilities(false));
when(uuidIncapableExpiredDevice.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(31));
when(uuidIncapableExpiredDevice.isEnabled()).thenReturn(false);
} }
@Test @Test
@ -80,4 +96,25 @@ public class AccountTest {
assertFalse(oldPrimaryAccount.isEnabled()); assertFalse(oldPrimaryAccount.isEnabled());
} }
@Test
public void testCapabilities() {
Account uuidCapable = new Account("+14152222222", UUID.randomUUID(), new HashSet<Device>() {{
add(uuidCapableDevice);
}}, "1234".getBytes());
Account uuidIncapable = new Account("+14152222222", UUID.randomUUID(), new HashSet<Device>() {{
add(uuidCapableDevice);
add(uuidIncapableDevice);
}}, "1234".getBytes());
Account uuidCapableWithExpiredIncapable = new Account("+14152222222", UUID.randomUUID(), new HashSet<Device>() {{
add(uuidCapableDevice);
add(uuidIncapableExpiredDevice);
}}, "1234".getBytes());
assertTrue(uuidCapable.isUuidAddressingSupported());
assertFalse(uuidIncapable.isUuidAddressingSupported());
assertTrue(uuidCapableWithExpiredIncapable.isUuidAddressingSupported());
}
} }

View File

@ -270,7 +270,7 @@ public class AccountsTest {
private Device generateDevice(long id) { private Device generateDevice(long id) {
Random random = new Random(System.currentTimeMillis()); Random random = new Random(System.currentTimeMillis());
SignedPreKey signedPreKey = new SignedPreKey(random.nextInt(), "testPublicKey-" + random.nextInt(), "testSignature-" + random.nextInt()); 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(), random.nextBoolean(), 0); 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()));
} }
private Account generateAccount(String number, UUID uuid) { private Account generateAccount(String number, UUID uuid) {