Include timestamps in all server-to-client websocket messages.

This commit is contained in:
Jon Chambers 2020-05-21 11:15:36 -04:00 committed by Jon Chambers
parent eb8b5e5c01
commit a25af36e32
4 changed files with 29 additions and 10 deletions

View File

@ -1,5 +1,7 @@
package org.whispersystems.textsecuregcm.filters; package org.whispersystems.textsecuregcm.filters;
import org.whispersystems.textsecuregcm.util.TimestampHeaderUtil;
import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext; import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter; import javax.ws.rs.container.ContainerResponseFilter;
@ -10,10 +12,8 @@ import java.util.Collections;
*/ */
public class TimestampResponseFilter implements ContainerResponseFilter { public class TimestampResponseFilter implements ContainerResponseFilter {
private static final String TIMESTAMP_HEADER = "X-Signal-Timestamp";
@Override @Override
public void filter(final ContainerRequestContext requestContext, final ContainerResponseContext responseContext) { public void filter(final ContainerRequestContext requestContext, final ContainerResponseContext responseContext) {
responseContext.getStringHeaders().put(TIMESTAMP_HEADER, Collections.singletonList(String.valueOf(System.currentTimeMillis()))); responseContext.getStringHeaders().put(TimestampHeaderUtil.TIMESTAMP_HEADER, Collections.singletonList(String.valueOf(System.currentTimeMillis())));
} }
} }

View File

@ -0,0 +1,13 @@
package org.whispersystems.textsecuregcm.util;
public class TimestampHeaderUtil {
public static final String TIMESTAMP_HEADER = "X-Signal-Timestamp";
private TimestampHeaderUtil() {
}
public static String getTimestampHeader() {
return TIMESTAMP_HEADER + ":" + System.currentTimeMillis();
}
}

View File

@ -6,8 +6,10 @@ import org.slf4j.LoggerFactory;
import org.whispersystems.dispatch.DispatchChannel; import org.whispersystems.dispatch.DispatchChannel;
import org.whispersystems.textsecuregcm.entities.MessageProtos.ProvisioningUuid; import org.whispersystems.textsecuregcm.entities.MessageProtos.ProvisioningUuid;
import org.whispersystems.textsecuregcm.storage.PubSubProtos.PubSubMessage; import org.whispersystems.textsecuregcm.storage.PubSubProtos.PubSubMessage;
import org.whispersystems.textsecuregcm.util.TimestampHeaderUtil;
import org.whispersystems.websocket.WebSocketClient; import org.whispersystems.websocket.WebSocketClient;
import java.util.Collections;
import java.util.Optional; import java.util.Optional;
public class ProvisioningConnection implements DispatchChannel { public class ProvisioningConnection implements DispatchChannel {
@ -28,7 +30,7 @@ public class ProvisioningConnection implements DispatchChannel {
if (outgoingMessage.getType() == PubSubMessage.Type.DELIVER) { if (outgoingMessage.getType() == PubSubMessage.Type.DELIVER) {
Optional<byte[]> body = Optional.of(outgoingMessage.getContent().toByteArray()); Optional<byte[]> body = Optional.of(outgoingMessage.getContent().toByteArray());
client.sendRequest("PUT", "/v1/message", null, body) client.sendRequest("PUT", "/v1/message", Collections.singletonList(TimestampHeaderUtil.getTimestampHeader()), body)
.thenAccept(response -> client.close(1001, "All you get.")) .thenAccept(response -> client.close(1001, "All you get."))
.exceptionally(throwable -> { .exceptionally(throwable -> {
client.close(1001, "That's all!"); client.close(1001, "That's all!");
@ -44,10 +46,12 @@ public class ProvisioningConnection implements DispatchChannel {
public void onDispatchSubscribed(String channel) { public void onDispatchSubscribed(String channel) {
try { try {
ProvisioningAddress address = new ProvisioningAddress(channel); ProvisioningAddress address = new ProvisioningAddress(channel);
this.client.sendRequest("PUT", "/v1/address", null, Optional.of(ProvisioningUuid.newBuilder() this.client.sendRequest("PUT", "/v1/address", Collections.singletonList(TimestampHeaderUtil.getTimestampHeader()),
.setUuid(address.getAddress()) Optional.of(ProvisioningUuid.newBuilder()
.build() .setUuid(address.getAddress())
.toByteArray())); .build()
.toByteArray()));
} catch (InvalidWebsocketAddressException e) { } catch (InvalidWebsocketAddressException e) {
logger.warn("Badly formatted address", e); logger.warn("Badly formatted address", e);
this.client.close(1001, "Server Error"); this.client.close(1001, "Server Error");

View File

@ -21,6 +21,7 @@ import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.MessagesManager; import org.whispersystems.textsecuregcm.storage.MessagesManager;
import org.whispersystems.textsecuregcm.util.Constants; import org.whispersystems.textsecuregcm.util.Constants;
import org.whispersystems.textsecuregcm.util.TimestampHeaderUtil;
import org.whispersystems.textsecuregcm.util.Util; import org.whispersystems.textsecuregcm.util.Util;
import org.whispersystems.websocket.WebSocketClient; import org.whispersystems.websocket.WebSocketClient;
import org.whispersystems.websocket.messages.WebSocketResponseMessage; import org.whispersystems.websocket.messages.WebSocketResponseMessage;
@ -28,6 +29,7 @@ import org.whispersystems.websocket.messages.WebSocketResponseMessage;
import javax.ws.rs.WebApplicationException; import javax.ws.rs.WebApplicationException;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import static com.codahale.metrics.MetricRegistry.name; import static com.codahale.metrics.MetricRegistry.name;
@ -118,7 +120,7 @@ public class WebSocketConnection implements DispatchChannel {
body = Optional.ofNullable(new EncryptedOutgoingMessage(message, device.getSignalingKey()).toByteArray()); body = Optional.ofNullable(new EncryptedOutgoingMessage(message, device.getSignalingKey()).toByteArray());
} }
client.sendRequest("PUT", "/api/v1/message", Collections.singletonList(header), body) client.sendRequest("PUT", "/api/v1/message", List.of(header, TimestampHeaderUtil.getTimestampHeader()), body)
.thenAccept(response -> { .thenAccept(response -> {
boolean isReceipt = message.getType() == Envelope.Type.RECEIPT; boolean isReceipt = message.getType() == Envelope.Type.RECEIPT;
@ -201,7 +203,7 @@ public class WebSocketConnection implements DispatchChannel {
} }
if (!messages.hasMore()) { if (!messages.hasMore()) {
client.sendRequest("PUT", "/api/v1/queue/empty", null, Optional.empty()); client.sendRequest("PUT", "/api/v1/queue/empty", Collections.singletonList(TimestampHeaderUtil.getTimestampHeader()), Optional.empty());
} }
} }