Add support for "registrationId" session enforcement.
This commit is contained in:
parent
35e212a30f
commit
f4ecb5d7be
2
pom.xml
2
pom.xml
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
<groupId>org.whispersystems.textsecure</groupId>
|
<groupId>org.whispersystems.textsecure</groupId>
|
||||||
<artifactId>TextSecureServer</artifactId>
|
<artifactId>TextSecureServer</artifactId>
|
||||||
<version>0.3</version>
|
<version>0.4</version>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -131,7 +131,7 @@ public class WhisperServerService extends Service<WhisperServerConfiguration> {
|
||||||
accountsManager);
|
accountsManager);
|
||||||
|
|
||||||
AttachmentController attachmentController = new AttachmentController(rateLimiters, federatedClientManager, urlSigner);
|
AttachmentController attachmentController = new AttachmentController(rateLimiters, federatedClientManager, urlSigner);
|
||||||
KeysController keysController = new KeysController(rateLimiters, keys, federatedClientManager);
|
KeysController keysController = new KeysController(rateLimiters, keys, accountsManager, federatedClientManager);
|
||||||
MessageController messageController = new MessageController(rateLimiters, pushSender, accountsManager, federatedClientManager);
|
MessageController messageController = new MessageController(rateLimiters, pushSender, accountsManager, federatedClientManager);
|
||||||
|
|
||||||
environment.addProvider(new MultiBasicAuthProvider<>(new FederatedPeerAuthenticator(config.getFederationConfiguration()),
|
environment.addProvider(new MultiBasicAuthProvider<>(new FederatedPeerAuthenticator(config.getFederationConfiguration()),
|
||||||
|
|
|
@ -140,6 +140,7 @@ public class AccountController {
|
||||||
device.setAuthenticationCredentials(new AuthenticationCredentials(password));
|
device.setAuthenticationCredentials(new AuthenticationCredentials(password));
|
||||||
device.setSignalingKey(accountAttributes.getSignalingKey());
|
device.setSignalingKey(accountAttributes.getSignalingKey());
|
||||||
device.setFetchesMessages(accountAttributes.getFetchesMessages());
|
device.setFetchesMessages(accountAttributes.getFetchesMessages());
|
||||||
|
device.setRegistrationId(accountAttributes.getRegistrationId());
|
||||||
|
|
||||||
Account account = new Account();
|
Account account = new Account();
|
||||||
account.setNumber(number);
|
account.setNumber(number);
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.whispersystems.textsecuregcm.federation.FederatedClientManager;
|
||||||
import org.whispersystems.textsecuregcm.federation.NoSuchPeerException;
|
import org.whispersystems.textsecuregcm.federation.NoSuchPeerException;
|
||||||
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||||
import org.whispersystems.textsecuregcm.storage.Account;
|
import org.whispersystems.textsecuregcm.storage.Account;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||||
import org.whispersystems.textsecuregcm.storage.Device;
|
import org.whispersystems.textsecuregcm.storage.Device;
|
||||||
import org.whispersystems.textsecuregcm.storage.Keys;
|
import org.whispersystems.textsecuregcm.storage.Keys;
|
||||||
|
|
||||||
|
@ -42,6 +43,8 @@ import javax.ws.rs.QueryParam;
|
||||||
import javax.ws.rs.WebApplicationException;
|
import javax.ws.rs.WebApplicationException;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Path("/v1/keys")
|
@Path("/v1/keys")
|
||||||
public class KeysController {
|
public class KeysController {
|
||||||
|
@ -50,13 +53,15 @@ public class KeysController {
|
||||||
|
|
||||||
private final RateLimiters rateLimiters;
|
private final RateLimiters rateLimiters;
|
||||||
private final Keys keys;
|
private final Keys keys;
|
||||||
|
private final AccountsManager accounts;
|
||||||
private final FederatedClientManager federatedClientManager;
|
private final FederatedClientManager federatedClientManager;
|
||||||
|
|
||||||
public KeysController(RateLimiters rateLimiters, Keys keys,
|
public KeysController(RateLimiters rateLimiters, Keys keys, AccountsManager accounts,
|
||||||
FederatedClientManager federatedClientManager)
|
FederatedClientManager federatedClientManager)
|
||||||
{
|
{
|
||||||
this.rateLimiters = rateLimiters;
|
this.rateLimiters = rateLimiters;
|
||||||
this.keys = keys;
|
this.keys = keys;
|
||||||
|
this.accounts = accounts;
|
||||||
this.federatedClientManager = federatedClientManager;
|
this.federatedClientManager = federatedClientManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,18 +113,50 @@ public class KeysController {
|
||||||
return results.getKeys().get(0);
|
return results.getKeys().get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<UnstructuredPreKeyList> getLocalKeys(String number, String deviceId) {
|
private Optional<UnstructuredPreKeyList> getLocalKeys(String number, String deviceIdSelector) {
|
||||||
|
Optional<Account> destination = accounts.get(number);
|
||||||
|
|
||||||
|
if (!destination.isPresent() || !destination.get().isActive()) {
|
||||||
|
return Optional.absent();
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (deviceId.equals("*")) {
|
if (deviceIdSelector.equals("*")) {
|
||||||
return keys.get(number);
|
Optional<UnstructuredPreKeyList> preKeys = keys.get(number);
|
||||||
|
return getActiveKeys(destination.get(), preKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<PreKey> targetKey = keys.get(number, Long.parseLong(deviceId));
|
long deviceId = Long.parseLong(deviceIdSelector);
|
||||||
|
Optional<Device> targetDevice = destination.get().getDevice(deviceId);
|
||||||
|
|
||||||
if (targetKey.isPresent()) return Optional.of(new UnstructuredPreKeyList(targetKey.get()));
|
if (!targetDevice.isPresent() || !targetDevice.get().isActive()) {
|
||||||
else return Optional.absent();
|
return Optional.absent();
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<UnstructuredPreKeyList> preKeys = keys.get(number, deviceId);
|
||||||
|
return getActiveKeys(destination.get(), preKeys);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
throw new WebApplicationException(Response.status(422).build());
|
throw new WebApplicationException(Response.status(422).build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Optional<UnstructuredPreKeyList> getActiveKeys(Account destination,
|
||||||
|
Optional<UnstructuredPreKeyList> preKeys)
|
||||||
|
{
|
||||||
|
if (!preKeys.isPresent()) return Optional.absent();
|
||||||
|
|
||||||
|
List<PreKey> filteredKeys = new LinkedList<>();
|
||||||
|
|
||||||
|
for (PreKey preKey : preKeys.get().getKeys()) {
|
||||||
|
Optional<Device> device = destination.getDevice(preKey.getDeviceId());
|
||||||
|
|
||||||
|
if (device.isPresent() && device.get().isActive()) {
|
||||||
|
preKey.setRegistrationId(device.get().getRegistrationId());
|
||||||
|
filteredKeys.add(preKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filteredKeys.isEmpty()) return Optional.absent();
|
||||||
|
else return Optional.of(new UnstructuredPreKeyList(filteredKeys));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import org.whispersystems.textsecuregcm.entities.IncomingMessageList;
|
||||||
import org.whispersystems.textsecuregcm.entities.MessageProtos.OutgoingMessageSignal;
|
import org.whispersystems.textsecuregcm.entities.MessageProtos.OutgoingMessageSignal;
|
||||||
import org.whispersystems.textsecuregcm.entities.MessageResponse;
|
import org.whispersystems.textsecuregcm.entities.MessageResponse;
|
||||||
import org.whispersystems.textsecuregcm.entities.MismatchedDevices;
|
import org.whispersystems.textsecuregcm.entities.MismatchedDevices;
|
||||||
|
import org.whispersystems.textsecuregcm.entities.StaleDevices;
|
||||||
import org.whispersystems.textsecuregcm.federation.FederatedClient;
|
import org.whispersystems.textsecuregcm.federation.FederatedClient;
|
||||||
import org.whispersystems.textsecuregcm.federation.FederatedClientManager;
|
import org.whispersystems.textsecuregcm.federation.FederatedClientManager;
|
||||||
import org.whispersystems.textsecuregcm.federation.NoSuchPeerException;
|
import org.whispersystems.textsecuregcm.federation.NoSuchPeerException;
|
||||||
|
@ -98,6 +99,11 @@ public class MessageController {
|
||||||
.entity(new MismatchedDevices(e.getMissingDevices(),
|
.entity(new MismatchedDevices(e.getMissingDevices(),
|
||||||
e.getExtraDevices()))
|
e.getExtraDevices()))
|
||||||
.build());
|
.build());
|
||||||
|
} catch (StaleDevicesException e) {
|
||||||
|
throw new WebApplicationException(Response.status(410)
|
||||||
|
.type(MediaType.APPLICATION_JSON)
|
||||||
|
.entity(new StaleDevices(e.getStaleDevices()))
|
||||||
|
.build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,11 +130,12 @@ public class MessageController {
|
||||||
private void sendLocalMessage(Account source,
|
private void sendLocalMessage(Account source,
|
||||||
String destinationName,
|
String destinationName,
|
||||||
IncomingMessageList messages)
|
IncomingMessageList messages)
|
||||||
throws NoSuchUserException, MismatchedDevicesException, IOException
|
throws NoSuchUserException, MismatchedDevicesException, IOException, StaleDevicesException
|
||||||
{
|
{
|
||||||
Account destination = getDestinationAccount(destinationName);
|
Account destination = getDestinationAccount(destinationName);
|
||||||
|
|
||||||
validateCompleteDeviceList(destination, messages.getMessages());
|
validateCompleteDeviceList(destination, messages.getMessages());
|
||||||
|
validateRegistrationIds(destination, messages.getMessages());
|
||||||
|
|
||||||
for (IncomingMessage incomingMessage : messages.getMessages()) {
|
for (IncomingMessage incomingMessage : messages.getMessages()) {
|
||||||
Optional<Device> destinationDevice = destination.getDevice(incomingMessage.getDestinationDeviceId());
|
Optional<Device> destinationDevice = destination.getDevice(incomingMessage.getDestinationDeviceId());
|
||||||
|
@ -197,6 +204,27 @@ public class MessageController {
|
||||||
return account.get();
|
return account.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validateRegistrationIds(Account account, List<IncomingMessage> messages)
|
||||||
|
throws StaleDevicesException
|
||||||
|
{
|
||||||
|
List<Long> staleDevices = new LinkedList<>();
|
||||||
|
|
||||||
|
for (IncomingMessage message : messages) {
|
||||||
|
Optional<Device> device = account.getDevice(message.getDestinationDeviceId());
|
||||||
|
|
||||||
|
if (device.isPresent() &&
|
||||||
|
message.getDestinationRegistrationId() > 0 &&
|
||||||
|
message.getDestinationRegistrationId() != device.get().getRegistrationId())
|
||||||
|
{
|
||||||
|
staleDevices.add(device.get().getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!staleDevices.isEmpty()) {
|
||||||
|
throw new StaleDevicesException(staleDevices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void validateCompleteDeviceList(Account account, List<IncomingMessage> messages)
|
private void validateCompleteDeviceList(Account account, List<IncomingMessage> messages)
|
||||||
throws MismatchedDevicesException
|
throws MismatchedDevicesException
|
||||||
{
|
{
|
||||||
|
@ -211,10 +239,12 @@ public class MessageController {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Device device : account.getDevices()) {
|
for (Device device : account.getDevices()) {
|
||||||
accountDeviceIds.add(device.getId());
|
if (device.isActive()) {
|
||||||
|
accountDeviceIds.add(device.getId());
|
||||||
|
|
||||||
if (!messageDeviceIds.contains(device.getId())) {
|
if (!messageDeviceIds.contains(device.getId())) {
|
||||||
missingDeviceIds.add(device.getId());
|
missingDeviceIds.add(device.getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package org.whispersystems.textsecuregcm.controllers;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
public class StaleDevicesException extends Throwable {
|
||||||
|
private final List<Long> staleDevices;
|
||||||
|
|
||||||
|
public StaleDevicesException(List<Long> staleDevices) {
|
||||||
|
this.staleDevices = staleDevices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Long> getStaleDevices() {
|
||||||
|
return staleDevices;
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,12 +31,16 @@ public class AccountAttributes {
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private boolean fetchesMessages;
|
private boolean fetchesMessages;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private int registrationId;
|
||||||
|
|
||||||
public AccountAttributes() {}
|
public AccountAttributes() {}
|
||||||
|
|
||||||
public AccountAttributes(String signalingKey, boolean supportsSms, boolean fetchesMessages) {
|
public AccountAttributes(String signalingKey, boolean supportsSms, boolean fetchesMessages, int registrationId) {
|
||||||
this.signalingKey = signalingKey;
|
this.signalingKey = signalingKey;
|
||||||
this.supportsSms = supportsSms;
|
this.supportsSms = supportsSms;
|
||||||
this.fetchesMessages = fetchesMessages;
|
this.fetchesMessages = fetchesMessages;
|
||||||
|
this.registrationId = registrationId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSignalingKey() {
|
public String getSignalingKey() {
|
||||||
|
@ -51,4 +55,7 @@ public class AccountAttributes {
|
||||||
return fetchesMessages;
|
return fetchesMessages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getRegistrationId() {
|
||||||
|
return registrationId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,9 @@ public class IncomingMessage {
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private long destinationDeviceId = 1;
|
private long destinationDeviceId = 1;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private int destinationRegistrationId;
|
||||||
|
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
@NotEmpty
|
@NotEmpty
|
||||||
private String body;
|
private String body;
|
||||||
|
@ -40,6 +43,7 @@ public class IncomingMessage {
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private long timestamp;
|
private long timestamp;
|
||||||
|
|
||||||
|
|
||||||
public String getDestination() {
|
public String getDestination() {
|
||||||
return destination;
|
return destination;
|
||||||
}
|
}
|
||||||
|
@ -59,4 +63,8 @@ public class IncomingMessage {
|
||||||
public long getDestinationDeviceId() {
|
public long getDestinationDeviceId() {
|
||||||
return destinationDeviceId;
|
return destinationDeviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getDestinationRegistrationId() {
|
||||||
|
return destinationRegistrationId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,9 @@ public class PreKey {
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private boolean lastResort;
|
private boolean lastResort;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private int registrationId;
|
||||||
|
|
||||||
public PreKey() {}
|
public PreKey() {}
|
||||||
|
|
||||||
public PreKey(long id, String number, long deviceId, long keyId,
|
public PreKey(long id, String number, long deviceId, long keyId,
|
||||||
|
@ -125,4 +128,12 @@ public class PreKey {
|
||||||
public long getDeviceId() {
|
public long getDeviceId() {
|
||||||
return deviceId;
|
return deviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getRegistrationId() {
|
||||||
|
return registrationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegistrationId(int registrationId) {
|
||||||
|
this.registrationId = registrationId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package org.whispersystems.textsecuregcm.entities;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class StaleDevices {
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private List<Long> staleDevices;
|
||||||
|
|
||||||
|
public StaleDevices() {}
|
||||||
|
|
||||||
|
public StaleDevices(List<Long> staleDevices) {
|
||||||
|
this.staleDevices = staleDevices;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -48,11 +48,14 @@ public class Device implements Serializable {
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private boolean fetchesMessages;
|
private boolean fetchesMessages;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private int registrationId;
|
||||||
|
|
||||||
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)
|
boolean fetchesMessages, int registrationId)
|
||||||
{
|
{
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.authToken = authToken;
|
this.authToken = authToken;
|
||||||
|
@ -61,6 +64,7 @@ public class Device implements Serializable {
|
||||||
this.gcmId = gcmId;
|
this.gcmId = gcmId;
|
||||||
this.apnId = apnId;
|
this.apnId = apnId;
|
||||||
this.fetchesMessages = fetchesMessages;
|
this.fetchesMessages = fetchesMessages;
|
||||||
|
this.registrationId = registrationId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getApnId() {
|
public String getApnId() {
|
||||||
|
@ -119,4 +123,12 @@ public class Device implements Serializable {
|
||||||
public boolean isMaster() {
|
public boolean isMaster() {
|
||||||
return getId() == MASTER_ID;
|
return getId() == MASTER_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getRegistrationId() {
|
||||||
|
return registrationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegistrationId(int registrationId) {
|
||||||
|
this.registrationId = registrationId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,14 +84,14 @@ public abstract class Keys {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transaction(TransactionIsolationLevel.SERIALIZABLE)
|
@Transaction(TransactionIsolationLevel.SERIALIZABLE)
|
||||||
public Optional<PreKey> get(String number, long deviceId) {
|
public Optional<UnstructuredPreKeyList> get(String number, long deviceId) {
|
||||||
PreKey preKey = retrieveFirst(number, deviceId);
|
PreKey preKey = retrieveFirst(number, deviceId);
|
||||||
|
|
||||||
if (preKey != null && !preKey.isLastResort()) {
|
if (preKey != null && !preKey.isLastResort()) {
|
||||||
removeKey(preKey.getId());
|
removeKey(preKey.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (preKey != null) return Optional.of(preKey);
|
if (preKey != null) return Optional.of(new UnstructuredPreKeyList(preKey));
|
||||||
else return Optional.absent();
|
else return Optional.absent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ public class AccountControllerTest extends ResourceTest {
|
||||||
ClientResponse response =
|
ClientResponse response =
|
||||||
client().resource(String.format("/v1/accounts/code/%s", "1234"))
|
client().resource(String.format("/v1/accounts/code/%s", "1234"))
|
||||||
.header("Authorization", AuthHelper.getAuthHeader(SENDER, "bar"))
|
.header("Authorization", AuthHelper.getAuthHeader(SENDER, "bar"))
|
||||||
.entity(new AccountAttributes("keykeykeykey", false, false))
|
.entity(new AccountAttributes("keykeykeykey", false, false, 2222))
|
||||||
.type(MediaType.APPLICATION_JSON_TYPE)
|
.type(MediaType.APPLICATION_JSON_TYPE)
|
||||||
.put(ClientResponse.class);
|
.put(ClientResponse.class);
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ public class AccountControllerTest extends ResourceTest {
|
||||||
ClientResponse response =
|
ClientResponse response =
|
||||||
client().resource(String.format("/v1/accounts/code/%s", "1111"))
|
client().resource(String.format("/v1/accounts/code/%s", "1111"))
|
||||||
.header("Authorization", AuthHelper.getAuthHeader(SENDER, "bar"))
|
.header("Authorization", AuthHelper.getAuthHeader(SENDER, "bar"))
|
||||||
.entity(new AccountAttributes("keykeykeykey", false, false))
|
.entity(new AccountAttributes("keykeykeykey", false, false, 3333))
|
||||||
.type(MediaType.APPLICATION_JSON_TYPE)
|
.type(MediaType.APPLICATION_JSON_TYPE)
|
||||||
.put(ClientResponse.class);
|
.put(ClientResponse.class);
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ public class DeviceControllerTest extends ResourceTest {
|
||||||
|
|
||||||
DeviceResponse response = client().resource("/v1/devices/5678901")
|
DeviceResponse response = client().resource("/v1/devices/5678901")
|
||||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, "password1"))
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, "password1"))
|
||||||
.entity(new AccountAttributes("keykeykeykey", false, true))
|
.entity(new AccountAttributes("keykeykeykey", false, true, 1234))
|
||||||
.type(MediaType.APPLICATION_JSON_TYPE)
|
.type(MediaType.APPLICATION_JSON_TYPE)
|
||||||
.put(DeviceResponse.class);
|
.put(DeviceResponse.class);
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@ import org.whispersystems.textsecuregcm.entities.PreKey;
|
||||||
import org.whispersystems.textsecuregcm.entities.UnstructuredPreKeyList;
|
import org.whispersystems.textsecuregcm.entities.UnstructuredPreKeyList;
|
||||||
import org.whispersystems.textsecuregcm.limits.RateLimiter;
|
import org.whispersystems.textsecuregcm.limits.RateLimiter;
|
||||||
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.Account;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||||
import org.whispersystems.textsecuregcm.storage.Device;
|
import org.whispersystems.textsecuregcm.storage.Device;
|
||||||
import org.whispersystems.textsecuregcm.storage.Keys;
|
import org.whispersystems.textsecuregcm.storage.Keys;
|
||||||
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||||
|
@ -24,9 +26,14 @@ public class KeyControllerTest extends ResourceTest {
|
||||||
private final String EXISTS_NUMBER = "+14152222222";
|
private final String EXISTS_NUMBER = "+14152222222";
|
||||||
private final String NOT_EXISTS_NUMBER = "+14152222220";
|
private final String NOT_EXISTS_NUMBER = "+14152222220";
|
||||||
|
|
||||||
private final PreKey SAMPLE_KEY = new PreKey(1, EXISTS_NUMBER, Device.MASTER_ID, 1234, "test1", "test2", false);
|
private final int SAMPLE_REGISTRATION_ID = 999;
|
||||||
private final PreKey SAMPLE_KEY2 = new PreKey(2, EXISTS_NUMBER, 2, 5667, "test3", "test4", false);
|
private final int SAMPLE_REGISTRATION_ID2 = 1002;
|
||||||
private final Keys keys = mock(Keys.class);
|
|
||||||
|
private final PreKey SAMPLE_KEY = new PreKey(1, EXISTS_NUMBER, Device.MASTER_ID, 1234, "test1", "test2", false);
|
||||||
|
private final PreKey SAMPLE_KEY2 = new PreKey(2, EXISTS_NUMBER, 2, 5667, "test3", "test4", false );
|
||||||
|
private final PreKey SAMPLE_KEY3 = new PreKey(3, EXISTS_NUMBER, 3, 334, "test5", "test6", false);
|
||||||
|
private final Keys keys = mock(Keys.class );
|
||||||
|
private final AccountsManager accounts = mock(AccountsManager.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setUpResources() {
|
protected void setUpResources() {
|
||||||
|
@ -35,17 +42,38 @@ public class KeyControllerTest extends ResourceTest {
|
||||||
RateLimiters rateLimiters = mock(RateLimiters.class);
|
RateLimiters rateLimiters = mock(RateLimiters.class);
|
||||||
RateLimiter rateLimiter = mock(RateLimiter.class );
|
RateLimiter rateLimiter = mock(RateLimiter.class );
|
||||||
|
|
||||||
|
Device sampleDevice = mock(Device.class );
|
||||||
|
Device sampleDevice2 = mock(Device.class);
|
||||||
|
Device sampleDevice3 = mock(Device.class);
|
||||||
|
Account existsAccount = mock(Account.class);
|
||||||
|
|
||||||
|
when(sampleDevice.getRegistrationId()).thenReturn(SAMPLE_REGISTRATION_ID);
|
||||||
|
when(sampleDevice2.getRegistrationId()).thenReturn(SAMPLE_REGISTRATION_ID2);
|
||||||
|
when(sampleDevice3.getRegistrationId()).thenReturn(SAMPLE_REGISTRATION_ID2);
|
||||||
|
when(sampleDevice.isActive()).thenReturn(true);
|
||||||
|
when(sampleDevice2.isActive()).thenReturn(true);
|
||||||
|
when(sampleDevice3.isActive()).thenReturn(false);
|
||||||
|
|
||||||
|
when(existsAccount.getDevice(1L)).thenReturn(Optional.of(sampleDevice));
|
||||||
|
when(existsAccount.getDevice(2L)).thenReturn(Optional.of(sampleDevice2));
|
||||||
|
when(existsAccount.getDevice(3L)).thenReturn(Optional.of(sampleDevice3));
|
||||||
|
when(existsAccount.isActive()).thenReturn(true);
|
||||||
|
|
||||||
|
when(accounts.get(EXISTS_NUMBER)).thenReturn(Optional.of(existsAccount));
|
||||||
|
when(accounts.get(NOT_EXISTS_NUMBER)).thenReturn(Optional.<Account>absent());
|
||||||
|
|
||||||
when(rateLimiters.getPreKeysLimiter()).thenReturn(rateLimiter);
|
when(rateLimiters.getPreKeysLimiter()).thenReturn(rateLimiter);
|
||||||
|
|
||||||
when(keys.get(eq(EXISTS_NUMBER), eq(1L))).thenReturn(Optional.of(SAMPLE_KEY));
|
when(keys.get(eq(EXISTS_NUMBER), eq(1L))).thenReturn(Optional.of(new UnstructuredPreKeyList(SAMPLE_KEY)));
|
||||||
when(keys.get(eq(NOT_EXISTS_NUMBER), eq(1L))).thenReturn(Optional.<PreKey>absent());
|
when(keys.get(eq(NOT_EXISTS_NUMBER), eq(1L))).thenReturn(Optional.<UnstructuredPreKeyList>absent());
|
||||||
|
|
||||||
List<PreKey> allKeys = new LinkedList<>();
|
List<PreKey> allKeys = new LinkedList<>();
|
||||||
allKeys.add(SAMPLE_KEY);
|
allKeys.add(SAMPLE_KEY);
|
||||||
allKeys.add(SAMPLE_KEY2);
|
allKeys.add(SAMPLE_KEY2);
|
||||||
|
allKeys.add(SAMPLE_KEY3);
|
||||||
when(keys.get(EXISTS_NUMBER)).thenReturn(Optional.of(new UnstructuredPreKeyList(allKeys)));
|
when(keys.get(EXISTS_NUMBER)).thenReturn(Optional.of(new UnstructuredPreKeyList(allKeys)));
|
||||||
|
|
||||||
addResource(new KeysController(rateLimiters, keys, null));
|
addResource(new KeysController(rateLimiters, keys, accounts, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -78,6 +106,7 @@ public class KeyControllerTest extends ResourceTest {
|
||||||
assertThat(result.getKeyId()).isEqualTo(SAMPLE_KEY.getKeyId());
|
assertThat(result.getKeyId()).isEqualTo(SAMPLE_KEY.getKeyId());
|
||||||
assertThat(result.getPublicKey()).isEqualTo(SAMPLE_KEY.getPublicKey());
|
assertThat(result.getPublicKey()).isEqualTo(SAMPLE_KEY.getPublicKey());
|
||||||
assertThat(result.getIdentityKey()).isEqualTo(SAMPLE_KEY.getIdentityKey());
|
assertThat(result.getIdentityKey()).isEqualTo(SAMPLE_KEY.getIdentityKey());
|
||||||
|
assertThat(result.getRegistrationId()).isEqualTo(SAMPLE_REGISTRATION_ID);
|
||||||
|
|
||||||
assertThat(result.getId() == 0);
|
assertThat(result.getId() == 0);
|
||||||
assertThat(result.getNumber() == null);
|
assertThat(result.getNumber() == null);
|
||||||
|
@ -86,6 +115,7 @@ public class KeyControllerTest extends ResourceTest {
|
||||||
assertThat(result.getKeyId()).isEqualTo(SAMPLE_KEY2.getKeyId());
|
assertThat(result.getKeyId()).isEqualTo(SAMPLE_KEY2.getKeyId());
|
||||||
assertThat(result.getPublicKey()).isEqualTo(SAMPLE_KEY2.getPublicKey());
|
assertThat(result.getPublicKey()).isEqualTo(SAMPLE_KEY2.getPublicKey());
|
||||||
assertThat(result.getIdentityKey()).isEqualTo(SAMPLE_KEY2.getIdentityKey());
|
assertThat(result.getIdentityKey()).isEqualTo(SAMPLE_KEY2.getIdentityKey());
|
||||||
|
assertThat(result.getRegistrationId()).isEqualTo(SAMPLE_REGISTRATION_ID2);
|
||||||
|
|
||||||
assertThat(result.getId() == 0);
|
assertThat(result.getId() == 0);
|
||||||
assertThat(result.getNumber() == null);
|
assertThat(result.getNumber() == null);
|
||||||
|
|
|
@ -53,12 +53,12 @@ public class MessageControllerTest extends ResourceTest {
|
||||||
addProvider(AuthHelper.getAuthenticator());
|
addProvider(AuthHelper.getAuthenticator());
|
||||||
|
|
||||||
List<Device> singleDeviceList = new LinkedList<Device>() {{
|
List<Device> singleDeviceList = new LinkedList<Device>() {{
|
||||||
add(new Device(1, "foo", "bar", "baz", "isgcm", null, false));
|
add(new Device(1, "foo", "bar", "baz", "isgcm", null, false, 111));
|
||||||
}};
|
}};
|
||||||
|
|
||||||
List<Device> multiDeviceList = new LinkedList<Device>() {{
|
List<Device> multiDeviceList = new LinkedList<Device>() {{
|
||||||
add(new Device(1, "foo", "bar", "baz", "isgcm", null, false));
|
add(new Device(1, "foo", "bar", "baz", "isgcm", null, false, 222));
|
||||||
add(new Device(2, "foo", "bar", "baz", "isgcm", null, false));
|
add(new Device(2, "foo", "bar", "baz", "isgcm", null, false, 333));
|
||||||
}};
|
}};
|
||||||
|
|
||||||
Account singleDeviceAccount = new Account(SINGLE_DEVICE_RECIPIENT, false, singleDeviceList);
|
Account singleDeviceAccount = new Account(SINGLE_DEVICE_RECIPIENT, false, singleDeviceList);
|
||||||
|
|
|
@ -15,6 +15,7 @@ public class PreKeyTest {
|
||||||
@Test
|
@Test
|
||||||
public void serializeToJSON() throws Exception {
|
public void serializeToJSON() throws Exception {
|
||||||
PreKey preKey = new PreKey(1, "+14152222222", 1, 1234, "test", "identityTest", false);
|
PreKey preKey = new PreKey(1, "+14152222222", 1, 1234, "test", "identityTest", false);
|
||||||
|
preKey.setRegistrationId(987);
|
||||||
|
|
||||||
assertThat("Basic Contact Serialization works",
|
assertThat("Basic Contact Serialization works",
|
||||||
asJson(preKey),
|
asJson(preKey),
|
||||||
|
|
|
@ -2,5 +2,6 @@
|
||||||
"deviceId" : 1,
|
"deviceId" : 1,
|
||||||
"keyId" : 1234,
|
"keyId" : 1234,
|
||||||
"publicKey" : "test",
|
"publicKey" : "test",
|
||||||
"identityKey" : "identityTest"
|
"identityKey" : "identityTest",
|
||||||
|
"registrationId" : 987
|
||||||
}
|
}
|
Loading…
Reference in New Issue