Support for expiration on APN messages.

// FREEBIE
This commit is contained in:
Moxie Marlinspike 2015-06-06 21:04:08 -07:00
parent 6f67a812dc
commit 83078a48ab
5 changed files with 42 additions and 22 deletions

View File

@ -25,7 +25,7 @@ message OutgoingMessageSignal {
CIPHERTEXT = 1;
KEY_EXCHANGE = 2;
PREKEY_BUNDLE = 3;
PLAINTEXT = 4;
// PLAINTEXT = 4;
RECEIPT = 5;
}

View File

@ -8,6 +8,9 @@ import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
public class ApnMessage {
public static long MAX_EXPIRATION = Integer.MAX_VALUE * 1000L;
@JsonProperty
@NotEmpty
private String apnId;
@ -28,22 +31,27 @@ public class ApnMessage {
@NotNull
private boolean voip;
@JsonProperty
private long expirationTime;
public ApnMessage() {}
public ApnMessage(String apnId, String number, int deviceId, String message, boolean voip) {
this.apnId = apnId;
this.number = number;
this.deviceId = deviceId;
this.message = message;
this.voip = voip;
public ApnMessage(String apnId, String number, int deviceId, String message, boolean voip, long expirationTime) {
this.apnId = apnId;
this.number = number;
this.deviceId = deviceId;
this.message = message;
this.voip = voip;
this.expirationTime = expirationTime;
}
public ApnMessage(ApnMessage copy, String apnId, boolean voip) {
this.apnId = apnId;
this.number = copy.number;
this.deviceId = copy.deviceId;
this.message = copy.message;
this.voip = voip;
public ApnMessage(ApnMessage copy, String apnId, boolean voip, long expirationTime) {
this.apnId = apnId;
this.number = copy.number;
this.deviceId = copy.deviceId;
this.message = copy.message;
this.voip = voip;
this.expirationTime = expirationTime;
}
@VisibleForTesting
@ -60,4 +68,9 @@ public class ApnMessage {
public String getMessage() {
return message;
}
@VisibleForTesting
public long getExpirationTime() {
return expirationTime;
}
}

View File

@ -71,7 +71,9 @@ public class ApnFallbackManager implements Managed, Runnable {
try {
Entry<WebsocketAddress, ApnFallbackTask> taskEntry = taskQueue.get();
ApnFallbackTask task = taskEntry.getValue();
pushServiceClient.send(new ApnMessage(task.getMessage(), task.getApnId(), false));
pushServiceClient.send(new ApnMessage(task.getMessage(), task.getApnId(),
false, ApnMessage.MAX_EXPIRATION));
} catch (Throwable e) {
logger.warn("ApnFallbackThread", e);
}

View File

@ -30,6 +30,7 @@ import org.whispersystems.textsecuregcm.util.Util;
import org.whispersystems.textsecuregcm.websocket.WebsocketAddress;
import java.util.LinkedHashMap;
import java.util.concurrent.TimeUnit;
import io.dropwizard.lifecycle.Managed;
import static org.whispersystems.textsecuregcm.entities.MessageProtos.OutgoingMessageSignal;
@ -107,16 +108,19 @@ public class PushSender {
DeliveryStatus deliveryStatus = webSocketSender.sendMessage(account, device, outgoingMessage, WebsocketSender.Type.APN);
if (!deliveryStatus.isDelivered() && outgoingMessage.getType() != OutgoingMessageSignal.Type.RECEIPT_VALUE) {
String apnId = Util.isEmpty(device.getVoipApnId()) ? device.getApnId() : device.getVoipApnId();
boolean isVoip = !Util.isEmpty(device.getVoipApnId());
ApnMessage apnMessage;
ApnMessage apnMessage = new ApnMessage(apnId, account.getNumber(), (int)device.getId(),
String.format(APN_PAYLOAD, deliveryStatus.getMessageQueueDepth()),
isVoip);
if (!Util.isEmpty(device.getVoipApnId())) {
apnMessage = new ApnMessage(device.getVoipApnId(), account.getNumber(), (int)device.getId(),
String.format(APN_PAYLOAD, deliveryStatus.getMessageQueueDepth()),
true, System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(30));
if (isVoip) {
apnFallbackManager.schedule(new WebsocketAddress(account.getNumber(), device.getId()),
new ApnFallbackTask(device.getApnId(), apnMessage));
} else {
apnMessage = new ApnMessage(device.getApnId(), account.getNumber(), (int)device.getId(),
String.format(APN_PAYLOAD, deliveryStatus.getMessageQueueDepth()),
false, ApnMessage.MAX_EXPIRATION);
}
pushServiceClient.send(apnMessage);

View File

@ -19,7 +19,7 @@ public class ApnFallbackManagerTest {
public void testFullFallback() throws Exception {
PushServiceClient pushServiceClient = mock(PushServiceClient.class);
WebsocketAddress address = mock(WebsocketAddress.class );
ApnMessage message = new ApnMessage("bar", "123", 1, "hmm", true);
ApnMessage message = new ApnMessage("bar", "123", 1, "hmm", true, 1111);
ApnFallbackTask task = new ApnFallbackTask("foo", message, 500);
ApnFallbackManager apnFallbackManager = new ApnFallbackManager(pushServiceClient);
@ -35,13 +35,14 @@ public class ApnFallbackManagerTest {
assertEquals(captor.getValue().getMessage(), message.getMessage());
assertEquals(captor.getValue().getApnId(), task.getApnId());
assertFalse(captor.getValue().isVoip());
assertEquals(captor.getValue().getExpirationTime(), Integer.MAX_VALUE * 1000L);
}
@Test
public void testNoFallback() throws Exception {
PushServiceClient pushServiceClient = mock(PushServiceClient.class);
WebsocketAddress address = mock(WebsocketAddress.class );
ApnMessage message = new ApnMessage("bar", "123", 1, "hmm", true);
ApnMessage message = new ApnMessage("bar", "123", 1, "hmm", true, 5555);
ApnFallbackTask task = new ApnFallbackTask ("foo", message, 500);
ApnFallbackManager apnFallbackManager = new ApnFallbackManager(pushServiceClient);