Device provisioning fixes.

// FREEBIE
This commit is contained in:
Moxie Marlinspike 2015-01-21 15:15:40 -08:00
parent f7132bdbbc
commit 45a0b74b89
13 changed files with 123 additions and 54 deletions

View File

@ -31,6 +31,7 @@ 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.PendingDevicesManager; import org.whispersystems.textsecuregcm.storage.PendingDevicesManager;
import org.whispersystems.textsecuregcm.util.Util;
import org.whispersystems.textsecuregcm.util.VerificationCode; import org.whispersystems.textsecuregcm.util.VerificationCode;
import javax.validation.Valid; import javax.validation.Valid;
@ -119,6 +120,7 @@ public class DeviceController {
device.setSignalingKey(accountAttributes.getSignalingKey()); device.setSignalingKey(accountAttributes.getSignalingKey());
device.setFetchesMessages(accountAttributes.getFetchesMessages()); device.setFetchesMessages(accountAttributes.getFetchesMessages());
device.setId(account.get().getNextDeviceId()); device.setId(account.get().getNextDeviceId());
device.setLastSeen(Util.todayInMillis());
account.get().addDevice(device); account.get().addDevice(device);
accounts.update(account.get()); accounts.update(account.get());

View File

@ -18,7 +18,7 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException; import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.Set;
import io.dropwizard.auth.Auth; import io.dropwizard.auth.Auth;
import static org.whispersystems.textsecuregcm.entities.MessageProtos.OutgoingMessageSignal; import static org.whispersystems.textsecuregcm.entities.MessageProtos.OutgoingMessageSignal;
@ -74,8 +74,8 @@ public class ReceiptController {
private void sendDirectReceipt(Account source, String destination, long messageId) private void sendDirectReceipt(Account source, String destination, long messageId)
throws NotPushRegisteredException, TransientPushFailureException, NoSuchUserException throws NotPushRegisteredException, TransientPushFailureException, NoSuchUserException
{ {
Account destinationAccount = getDestinationAccount(destination); Account destinationAccount = getDestinationAccount(destination);
List<Device> destinationDevices = destinationAccount.getDevices(); Set<Device> destinationDevices = destinationAccount.getDevices();
OutgoingMessageSignal.Builder message = OutgoingMessageSignal.Builder message =
OutgoingMessageSignal.newBuilder() OutgoingMessageSignal.newBuilder()

View File

@ -16,6 +16,7 @@
*/ */
package org.whispersystems.textsecuregcm.entities; package org.whispersystems.textsecuregcm.entities;
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;
@ -42,7 +43,19 @@ public class PreKeyResponseV2 {
} }
@VisibleForTesting @VisibleForTesting
public List<PreKeyResponseItemV2> getDevices() { @JsonIgnore
return devices; public PreKeyResponseItemV2 getDevice(int deviceId) {
for (PreKeyResponseItemV2 device : devices) {
if (device.getDeviceId() == deviceId) return device;
}
return null;
} }
@VisibleForTesting
@JsonIgnore
public int getDevicesCount() {
return devices.size();
}
} }

View File

@ -40,6 +40,6 @@ public class NonLimitedAccount extends Account {
@Override @Override
public Optional<Device> getAuthenticatedDevice() { public Optional<Device> getAuthenticatedDevice() {
return Optional.of(new Device(deviceId, null, null, null, null, null, false, 0, null)); return Optional.of(new Device(deviceId, null, null, null, null, null, false, 0, null, System.currentTimeMillis()));
} }
} }

View File

@ -22,8 +22,8 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import java.util.LinkedList; import java.util.HashSet;
import java.util.List; import java.util.Set;
public class Account { public class Account {
@ -36,7 +36,7 @@ public class Account {
private boolean supportsSms; private boolean supportsSms;
@JsonProperty @JsonProperty
private List<Device> devices = new LinkedList<>(); private Set<Device> devices = new HashSet<>();
@JsonProperty @JsonProperty
private String identityKey; private String identityKey;
@ -47,7 +47,7 @@ public class Account {
public Account() {} public Account() {}
@VisibleForTesting @VisibleForTesting
public Account(String number, boolean supportsSms, List<Device> devices) { public Account(String number, boolean supportsSms, Set<Device> devices) {
this.number = number; this.number = number;
this.supportsSms = supportsSms; this.supportsSms = supportsSms;
this.devices = devices; this.devices = devices;
@ -78,14 +78,11 @@ public class Account {
} }
public void addDevice(Device device) { public void addDevice(Device device) {
this.devices.remove(device);
this.devices.add(device); this.devices.add(device);
} }
public void setDevices(List<Device> devices) { public Set<Device> getDevices() {
this.devices = devices;
}
public List<Device> getDevices() {
return devices; return devices;
} }
@ -113,7 +110,9 @@ public class Account {
long highestDevice = Device.MASTER_ID; long highestDevice = Device.MASTER_ID;
for (Device device : devices) { for (Device device : devices) {
if (device.getId() > highestDevice) { if (!device.isActive()) {
return device.getId();
} else if (device.getId() > highestDevice) {
highestDevice = device.getId(); highestDevice = device.getId();
} }
} }

View File

@ -22,6 +22,8 @@ import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials;
import org.whispersystems.textsecuregcm.entities.SignedPreKey; import org.whispersystems.textsecuregcm.entities.SignedPreKey;
import org.whispersystems.textsecuregcm.util.Util; import org.whispersystems.textsecuregcm.util.Util;
import java.util.concurrent.TimeUnit;
public class Device { public class Device {
public static final long MASTER_ID = 1; public static final long MASTER_ID = 1;
@ -56,12 +58,15 @@ public class Device {
@JsonProperty @JsonProperty
private SignedPreKey signedPreKey; private SignedPreKey signedPreKey;
@JsonProperty
private long lastSeen;
public Device() {} public Device() {}
public Device(long id, String authToken, String salt, public Device(long id, String authToken, String salt,
String signalingKey, String gcmId, String apnId, String signalingKey, String gcmId, String apnId,
boolean fetchesMessages, int registrationId, boolean fetchesMessages, int registrationId,
SignedPreKey signedPreKey) SignedPreKey signedPreKey, long lastSeen)
{ {
this.id = id; this.id = id;
this.authToken = authToken; this.authToken = authToken;
@ -72,6 +77,7 @@ public class Device {
this.fetchesMessages = fetchesMessages; this.fetchesMessages = fetchesMessages;
this.registrationId = registrationId; this.registrationId = registrationId;
this.signedPreKey = signedPreKey; this.signedPreKey = signedPreKey;
this.lastSeen = lastSeen;
} }
public String getApnId() { public String getApnId() {
@ -86,6 +92,14 @@ public class Device {
} }
} }
public void setLastSeen(long lastSeen) {
this.lastSeen = lastSeen;
}
public long getLastSeen() {
return lastSeen;
}
public String getGcmId() { public String getGcmId() {
return gcmId; return gcmId;
} }
@ -124,7 +138,10 @@ public class Device {
} }
public boolean isActive() { public boolean isActive() {
return fetchesMessages || !Util.isEmpty(getApnId()) || !Util.isEmpty(getGcmId()); boolean hasChannel = fetchesMessages || !Util.isEmpty(getApnId()) || !Util.isEmpty(getGcmId());
return (id == MASTER_ID && hasChannel) ||
(id != MASTER_ID && hasChannel && signedPreKey != null && lastSeen > (System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30)));
} }
public boolean getFetchesMessages() { public boolean getFetchesMessages() {
@ -158,4 +175,17 @@ public class Device {
public long getPushTimestamp() { public long getPushTimestamp() {
return pushTimestamp; return pushTimestamp;
} }
@Override
public boolean equals(Object other) {
if (other == null || !(other instanceof Device)) return false;
Device that = (Device)other;
return this.id == that.id;
}
@Override
public int hashCode() {
return (int)this.id;
}
} }

View File

@ -21,6 +21,7 @@ import java.net.URLEncoder;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit;
public class Util { public class Util {
@ -119,4 +120,8 @@ public class Util {
Thread.sleep(i); Thread.sleep(i);
} catch (InterruptedException ie) {} } catch (InterruptedException ie) {}
} }
public static long todayInMillis() {
return TimeUnit.DAYS.toMillis(TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis()));
}
} }

View File

@ -9,6 +9,7 @@ import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.PubSubManager; import org.whispersystems.textsecuregcm.storage.PubSubManager;
import org.whispersystems.textsecuregcm.storage.StoredMessages; import org.whispersystems.textsecuregcm.storage.StoredMessages;
import org.whispersystems.textsecuregcm.util.Util;
import org.whispersystems.websocket.session.WebSocketSessionContext; import org.whispersystems.websocket.session.WebSocketSessionContext;
import org.whispersystems.websocket.setup.WebSocketConnectListener; import org.whispersystems.websocket.setup.WebSocketConnectListener;
@ -48,6 +49,11 @@ public class AuthenticatedConnectListener implements WebSocketConnectListener {
return; return;
} }
if (device.get().getLastSeen() != Util.todayInMillis()) {
device.get().setLastSeen(Util.todayInMillis());
accountsManager.update(account.get());
}
final WebSocketConnection connection = new WebSocketConnection(accountsManager, pushSender, final WebSocketConnection connection = new WebSocketConnection(accountsManager, pushSender,
storedMessages, pubSubManager, storedMessages, pubSubManager,
account.get(), device.get(), account.get(), device.get(),

View File

@ -27,8 +27,10 @@ import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.tests.util.AuthHelper; import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set;
import io.dropwizard.testing.junit.ResourceTestRule; import io.dropwizard.testing.junit.ResourceTestRule;
import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.equalTo;
@ -69,13 +71,13 @@ public class FederatedControllerTest {
@Before @Before
public void setup() throws Exception { public void setup() throws Exception {
List<Device> singleDeviceList = new LinkedList<Device>() {{ Set<Device> singleDeviceList = new HashSet<Device>() {{
add(new Device(1, "foo", "bar", "baz", "isgcm", null, false, 111, null)); add(new Device(1, "foo", "bar", "baz", "isgcm", null, false, 111, null, System.currentTimeMillis()));
}}; }};
List<Device> multiDeviceList = new LinkedList<Device>() {{ Set<Device> multiDeviceList = new HashSet<Device>() {{
add(new Device(1, "foo", "bar", "baz", "isgcm", null, false, 222, null)); add(new Device(1, "foo", "bar", "baz", "isgcm", null, false, 222, null, System.currentTimeMillis()));
add(new Device(2, "foo", "bar", "baz", "isgcm", null, false, 333, null)); add(new Device(2, "foo", "bar", "baz", "isgcm", null, false, 333, null, System.currentTimeMillis()));
}}; }};
Account singleDeviceAccount = new Account(SINGLE_DEVICE_RECIPIENT, false, singleDeviceList); Account singleDeviceAccount = new Account(SINGLE_DEVICE_RECIPIENT, false, singleDeviceList);

View File

@ -26,8 +26,10 @@ import org.whispersystems.textsecuregcm.storage.Keys;
import org.whispersystems.textsecuregcm.tests.util.AuthHelper; import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set;
import io.dropwizard.testing.junit.ResourceTestRule; import io.dropwizard.testing.junit.ResourceTestRule;
import static org.fest.assertions.api.Assertions.assertThat; import static org.fest.assertions.api.Assertions.assertThat;
@ -73,7 +75,7 @@ public class KeyControllerTest {
final Device sampleDevice3 = mock(Device.class); final Device sampleDevice3 = mock(Device.class);
final Device sampleDevice4 = mock(Device.class); final Device sampleDevice4 = mock(Device.class);
List<Device> allDevices = new LinkedList<Device>() {{ Set<Device> allDevices = new HashSet<Device>() {{
add(sampleDevice); add(sampleDevice);
add(sampleDevice2); add(sampleDevice2);
add(sampleDevice3); add(sampleDevice3);
@ -198,10 +200,10 @@ public class KeyControllerTest {
.get(PreKeyResponseV2.class); .get(PreKeyResponseV2.class);
assertThat(result.getIdentityKey()).isEqualTo(existsAccount.getIdentityKey()); assertThat(result.getIdentityKey()).isEqualTo(existsAccount.getIdentityKey());
assertThat(result.getDevices().size()).isEqualTo(1); assertThat(result.getDevicesCount()).isEqualTo(1);
assertThat(result.getDevices().get(0).getPreKey().getKeyId()).isEqualTo(SAMPLE_KEY.getKeyId()); assertThat(result.getDevice(1).getPreKey().getKeyId()).isEqualTo(SAMPLE_KEY.getKeyId());
assertThat(result.getDevices().get(0).getPreKey().getPublicKey()).isEqualTo(SAMPLE_KEY.getPublicKey()); assertThat(result.getDevice(1).getPreKey().getPublicKey()).isEqualTo(SAMPLE_KEY.getPublicKey());
assertThat(result.getDevices().get(0).getSignedPreKey()).isEqualTo(existsAccount.getDevice(1).get().getSignedPreKey()); assertThat(result.getDevice(1).getSignedPreKey()).isEqualTo(existsAccount.getDevice(1).get().getSignedPreKey());
verify(keys).get(eq(EXISTS_NUMBER), eq(1L)); verify(keys).get(eq(EXISTS_NUMBER), eq(1L));
verifyNoMoreInteractions(keys); verifyNoMoreInteractions(keys);
@ -245,13 +247,13 @@ public class KeyControllerTest {
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(PreKeyResponseV2.class); .get(PreKeyResponseV2.class);
assertThat(results.getDevices().size()).isEqualTo(3); assertThat(results.getDevicesCount()).isEqualTo(3);
assertThat(results.getIdentityKey()).isEqualTo(existsAccount.getIdentityKey()); assertThat(results.getIdentityKey()).isEqualTo(existsAccount.getIdentityKey());
PreKeyV2 signedPreKey = results.getDevices().get(0).getSignedPreKey(); PreKeyV2 signedPreKey = results.getDevice(1).getSignedPreKey();
PreKeyV2 preKey = results.getDevices().get(0).getPreKey(); PreKeyV2 preKey = results.getDevice(1).getPreKey();
long registrationId = results.getDevices().get(0).getRegistrationId(); long registrationId = results.getDevice(1).getRegistrationId();
long deviceId = results.getDevices().get(0).getDeviceId(); long deviceId = results.getDevice(1).getDeviceId();
assertThat(preKey.getKeyId()).isEqualTo(SAMPLE_KEY.getKeyId()); assertThat(preKey.getKeyId()).isEqualTo(SAMPLE_KEY.getKeyId());
assertThat(preKey.getPublicKey()).isEqualTo(SAMPLE_KEY.getPublicKey()); assertThat(preKey.getPublicKey()).isEqualTo(SAMPLE_KEY.getPublicKey());
@ -260,10 +262,10 @@ public class KeyControllerTest {
assertThat(signedPreKey.getPublicKey()).isEqualTo(SAMPLE_SIGNED_KEY.getPublicKey()); assertThat(signedPreKey.getPublicKey()).isEqualTo(SAMPLE_SIGNED_KEY.getPublicKey());
assertThat(deviceId).isEqualTo(1); assertThat(deviceId).isEqualTo(1);
signedPreKey = results.getDevices().get(1).getSignedPreKey(); signedPreKey = results.getDevice(2).getSignedPreKey();
preKey = results.getDevices().get(1).getPreKey(); preKey = results.getDevice(2).getPreKey();
registrationId = results.getDevices().get(1).getRegistrationId(); registrationId = results.getDevice(2).getRegistrationId();
deviceId = results.getDevices().get(1).getDeviceId(); deviceId = results.getDevice(2).getDeviceId();
assertThat(preKey.getKeyId()).isEqualTo(SAMPLE_KEY2.getKeyId()); assertThat(preKey.getKeyId()).isEqualTo(SAMPLE_KEY2.getKeyId());
assertThat(preKey.getPublicKey()).isEqualTo(SAMPLE_KEY2.getPublicKey()); assertThat(preKey.getPublicKey()).isEqualTo(SAMPLE_KEY2.getPublicKey());
@ -272,10 +274,10 @@ public class KeyControllerTest {
assertThat(signedPreKey.getPublicKey()).isEqualTo(SAMPLE_SIGNED_KEY2.getPublicKey()); assertThat(signedPreKey.getPublicKey()).isEqualTo(SAMPLE_SIGNED_KEY2.getPublicKey());
assertThat(deviceId).isEqualTo(2); assertThat(deviceId).isEqualTo(2);
signedPreKey = results.getDevices().get(2).getSignedPreKey(); signedPreKey = results.getDevice(4).getSignedPreKey();
preKey = results.getDevices().get(2).getPreKey(); preKey = results.getDevice(4).getPreKey();
registrationId = results.getDevices().get(2).getRegistrationId(); registrationId = results.getDevice(4).getRegistrationId();
deviceId = results.getDevices().get(2).getDeviceId(); deviceId = results.getDevice(4).getDeviceId();
assertThat(preKey.getKeyId()).isEqualTo(SAMPLE_KEY4.getKeyId()); assertThat(preKey.getKeyId()).isEqualTo(SAMPLE_KEY4.getKeyId());
assertThat(preKey.getPublicKey()).isEqualTo(SAMPLE_KEY4.getPublicKey()); assertThat(preKey.getPublicKey()).isEqualTo(SAMPLE_KEY4.getPublicKey());

View File

@ -6,10 +6,13 @@ import com.sun.jersey.api.client.ClientResponse;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.controllers.MessageController; import org.whispersystems.textsecuregcm.controllers.MessageController;
import org.whispersystems.textsecuregcm.entities.IncomingMessageList; import org.whispersystems.textsecuregcm.entities.IncomingMessageList;
import org.whispersystems.textsecuregcm.entities.MessageProtos; import org.whispersystems.textsecuregcm.entities.MessageProtos;
import org.whispersystems.textsecuregcm.entities.MismatchedDevices; import org.whispersystems.textsecuregcm.entities.MismatchedDevices;
import org.whispersystems.textsecuregcm.entities.SignedPreKey;
import org.whispersystems.textsecuregcm.entities.StaleDevices; import org.whispersystems.textsecuregcm.entities.StaleDevices;
import org.whispersystems.textsecuregcm.federation.FederatedClientManager; import org.whispersystems.textsecuregcm.federation.FederatedClientManager;
import org.whispersystems.textsecuregcm.limits.RateLimiter; import org.whispersystems.textsecuregcm.limits.RateLimiter;
@ -21,8 +24,9 @@ import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.tests.util.AuthHelper; import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import java.util.LinkedList; import java.util.HashSet;
import java.util.List; import java.util.Set;
import java.util.concurrent.TimeUnit;
import io.dropwizard.testing.junit.ResourceTestRule; import io.dropwizard.testing.junit.ResourceTestRule;
import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.equalTo;
@ -57,13 +61,14 @@ public class MessageControllerTest {
@Before @Before
public void setup() throws Exception { public void setup() throws Exception {
List<Device> singleDeviceList = new LinkedList<Device>() {{ Set<Device> singleDeviceList = new HashSet<Device>() {{
add(new Device(1, "foo", "bar", "baz", "isgcm", null, false, 111, null)); add(new Device(1, "foo", "bar", "baz", "isgcm", null, false, 111, null, System.currentTimeMillis()));
}}; }};
List<Device> multiDeviceList = new LinkedList<Device>() {{ Set<Device> multiDeviceList = new HashSet<Device>() {{
add(new Device(1, "foo", "bar", "baz", "isgcm", null, false, 222, null)); add(new Device(1, "foo", "bar", "baz", "isgcm", null, false, 222, new SignedPreKey(111, "foo", "bar"), System.currentTimeMillis()));
add(new Device(2, "foo", "bar", "baz", "isgcm", null, false, 333, null)); add(new Device(2, "foo", "bar", "baz", "isgcm", null, false, 333, new SignedPreKey(222, "oof", "rab"), System.currentTimeMillis()));
add(new Device(3, "foo", "bar", "baz", "isgcm", null, false, 444, null, System.currentTimeMillis() - TimeUnit.DAYS.toMillis(31)));
}}; }};
Account singleDeviceAccount = new Account(SINGLE_DEVICE_RECIPIENT, false, singleDeviceList); Account singleDeviceAccount = new Account(SINGLE_DEVICE_RECIPIENT, false, singleDeviceList);

View File

@ -18,8 +18,11 @@ import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.tests.util.AuthHelper; import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import io.dropwizard.testing.junit.ResourceTestRule; import io.dropwizard.testing.junit.ResourceTestRule;
import static org.fest.assertions.api.Assertions.assertThat; import static org.fest.assertions.api.Assertions.assertThat;
@ -47,13 +50,13 @@ public class ReceiptControllerTest {
@Before @Before
public void setup() throws Exception { public void setup() throws Exception {
List<Device> singleDeviceList = new LinkedList<Device>() {{ Set<Device> singleDeviceList = new HashSet<Device>() {{
add(new Device(1, "foo", "bar", "baz", "isgcm", null, false, 111, null)); add(new Device(1, "foo", "bar", "baz", "isgcm", null, false, 111, null, System.currentTimeMillis()));
}}; }};
List<Device> multiDeviceList = new LinkedList<Device>() {{ Set<Device> multiDeviceList = new HashSet<Device>() {{
add(new Device(1, "foo", "bar", "baz", "isgcm", null, false, 222, null)); add(new Device(1, "foo", "bar", "baz", "isgcm", null, false, 222, null, System.currentTimeMillis()));
add(new Device(2, "foo", "bar", "baz", "isgcm", null, false, 333, null)); add(new Device(2, "foo", "bar", "baz", "isgcm", null, false, 333, null, System.currentTimeMillis()));
}}; }};
Account singleDeviceAccount = new Account(SINGLE_DEVICE_RECIPIENT, false, singleDeviceList); Account singleDeviceAccount = new Account(SINGLE_DEVICE_RECIPIENT, false, singleDeviceList);

View File

@ -25,8 +25,10 @@ import org.whispersystems.websocket.session.WebSocketSessionContext;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set;
import io.dropwizard.auth.basic.BasicCredentials; import io.dropwizard.auth.basic.BasicCredentials;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@ -127,7 +129,7 @@ public class WebSocketConnectionTest {
final Device sender1device = mock(Device.class); final Device sender1device = mock(Device.class);
List<Device> sender1devices = new LinkedList<Device>() {{ Set<Device> sender1devices = new HashSet<Device>() {{
add(sender1device); add(sender1device);
}}; }};