diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java index fb52866bf..e40685ceb 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java @@ -520,29 +520,19 @@ public class MessageController { String userAgentString) throws NoSuchUserException { try { - Optional messageContent = getMessageContent(incomingMessage); - Envelope.Builder messageBuilder = Envelope.newBuilder(); + final Envelope envelope; - final Envelope.Type envelopeType = Envelope.Type.forNumber(incomingMessage.type()); - - if (envelopeType == null) { + try { + envelope = incomingMessage.toEnvelope(destinationUuid, + source.map(AuthenticatedAccount::getAccount).orElse(null), + source.map(authenticatedAccount -> authenticatedAccount.getAuthenticatedDevice().getId()).orElse(null), + timestamp == 0 ? System.currentTimeMillis() : timestamp); + } catch (final IllegalArgumentException e) { logger.warn("Received bad envelope type {} from {}", incomingMessage.type(), userAgentString); - throw new BadRequestException(); + throw new BadRequestException(e); } - messageBuilder.setType(envelopeType) - .setTimestamp(timestamp == 0 ? System.currentTimeMillis() : timestamp) - .setServerTimestamp(System.currentTimeMillis()) - .setDestinationUuid(destinationUuid.toString()); - - source.ifPresent(authenticatedAccount -> - messageBuilder.setSource(authenticatedAccount.getAccount().getNumber()) - .setSourceUuid(authenticatedAccount.getAccount().getUuid().toString()) - .setSourceDevice((int) authenticatedAccount.getAuthenticatedDevice().getId())); - - messageContent.ifPresent(bytes -> messageBuilder.setContent(ByteString.copyFrom(bytes))); - - messageSender.sendMessage(destinationAccount, destinationDevice, messageBuilder.build(), online); + messageSender.sendMessage(destinationAccount, destinationDevice, envelope, online); } catch (NotPushRegisteredException e) { if (destinationDevice.isMaster()) throw new NoSuchUserException(e); else logger.debug("Not registered", e); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/entities/IncomingMessage.java b/service/src/main/java/org/whispersystems/textsecuregcm/entities/IncomingMessage.java index 31abd9764..75fe68df9 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/entities/IncomingMessage.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/entities/IncomingMessage.java @@ -4,6 +4,39 @@ */ package org.whispersystems.textsecuregcm.entities; -public record IncomingMessage(int type, long destinationDeviceId, int destinationRegistrationId, - String content) { +import com.google.protobuf.ByteString; +import org.apache.commons.lang3.StringUtils; +import org.whispersystems.textsecuregcm.storage.Account; +import javax.annotation.Nullable; +import java.util.Base64; +import java.util.UUID; + +public record IncomingMessage(int type, long destinationDeviceId, int destinationRegistrationId, String content) { + + public MessageProtos.Envelope toEnvelope(final UUID destinationUuid, @Nullable Account sourceAccount, @Nullable Long sourceDeviceId, final long timestamp) { + final MessageProtos.Envelope.Type envelopeType = MessageProtos.Envelope.Type.forNumber(type()); + + if (envelopeType == null) { + throw new IllegalArgumentException("Bad envelope type: " + type()); + } + + final MessageProtos.Envelope.Builder envelopeBuilder = MessageProtos.Envelope.newBuilder(); + + envelopeBuilder.setType(envelopeType) + .setTimestamp(timestamp) + .setServerTimestamp(System.currentTimeMillis()) + .setDestinationUuid(destinationUuid.toString()); + + if (sourceAccount != null && sourceDeviceId != null) { + envelopeBuilder.setSource(sourceAccount.getNumber()) + .setSourceUuid(sourceAccount.getUuid().toString()) + .setSourceDevice(sourceDeviceId.intValue()); + } + + if (StringUtils.isNotEmpty(content())) { + envelopeBuilder.setContent(ByteString.copyFrom(Base64.getDecoder().decode(content()))); + } + + return envelopeBuilder.build(); + } } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/entities/OutgoingMessageEntity.java b/service/src/main/java/org/whispersystems/textsecuregcm/entities/OutgoingMessageEntity.java index 87f2ffb34..964d350dc 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/entities/OutgoingMessageEntity.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/entities/OutgoingMessageEntity.java @@ -5,8 +5,8 @@ package org.whispersystems.textsecuregcm.entities; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.protobuf.ByteString; +import org.apache.commons.lang3.StringUtils; import java.util.Arrays; import java.util.Objects; import java.util.UUID; @@ -15,6 +15,34 @@ public record OutgoingMessageEntity(UUID guid, int type, long timestamp, String int sourceDevice, UUID destinationUuid, UUID updatedPni, byte[] content, long serverTimestamp) { + public MessageProtos.Envelope toEnvelope() { + final MessageProtos.Envelope.Builder builder = MessageProtos.Envelope.newBuilder() + .setType(MessageProtos.Envelope.Type.forNumber(type())) + .setTimestamp(timestamp()) + .setServerTimestamp(serverTimestamp()) + .setDestinationUuid(destinationUuid().toString()) + .setServerGuid(guid().toString()); + + if (StringUtils.isNotEmpty(source())) { + builder.setSource(source()) + .setSourceDevice(sourceDevice()); + + if (sourceUuid() != null) { + builder.setSourceUuid(sourceUuid().toString()); + } + } + + if (content() != null) { + builder.setContent(ByteString.copyFrom(content())); + } + + if (updatedPni() != null) { + builder.setUpdatedPni(updatedPni().toString()); + } + + return builder.build(); + } + @Override public boolean equals(final Object o) { if (this == o) { diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/websocket/WebSocketConnection.java b/service/src/main/java/org/whispersystems/textsecuregcm/websocket/WebSocketConnection.java index eb1f7e263..a6b0e06b7 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/websocket/WebSocketConnection.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/websocket/WebSocketConnection.java @@ -13,9 +13,9 @@ import com.codahale.metrics.Meter; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.SharedMetricRegistries; import com.google.common.annotations.VisibleForTesting; -import com.google.protobuf.ByteString; import io.micrometer.core.instrument.Metrics; import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Tags; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -33,7 +33,6 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.LongAdder; import javax.ws.rs.WebApplicationException; -import io.micrometer.core.instrument.Tags; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,7 +49,6 @@ import org.whispersystems.textsecuregcm.storage.MessageAvailabilityListener; import org.whispersystems.textsecuregcm.storage.MessagesManager; import org.whispersystems.textsecuregcm.util.Constants; import org.whispersystems.textsecuregcm.util.TimestampHeaderUtil; -import org.whispersystems.textsecuregcm.util.Util; import org.whispersystems.textsecuregcm.util.ua.ClientPlatform; import org.whispersystems.textsecuregcm.util.ua.UnrecognizedUserAgentException; import org.whispersystems.textsecuregcm.util.ua.UserAgentUtil; @@ -314,33 +312,7 @@ public class WebSocketConnection implements MessageAvailabilityListener, Displac for (int i = 0; i < messages.messages().size(); i++) { final OutgoingMessageEntity message = messages.messages().get(i); - final Envelope.Builder builder = Envelope.newBuilder() - .setType(Envelope.Type.forNumber(message.type())) - .setTimestamp(message.timestamp()) - .setServerTimestamp(message.serverTimestamp()); - - if (!Util.isEmpty(message.source())) { - builder.setSource(message.source()) - .setSourceDevice(message.sourceDevice()); - if (message.sourceUuid() != null) { - builder.setSourceUuid(message.sourceUuid().toString()); - } - } - - if (message.content() != null) { - builder.setContent(ByteString.copyFrom(message.content())); - } - - builder.setDestinationUuid(message.destinationUuid().toString()); - - if (message.updatedPni() != null) { - builder.setUpdatedPni(message.updatedPni().toString()); - } - - builder.setServerGuid(message.guid().toString()); - - - final Envelope envelope = builder.build(); + final Envelope envelope = message.toEnvelope(); if (envelope.getSerializedSize() > MAX_DESKTOP_MESSAGE_SIZE && isDesktopClient) { messagesManager.delete(auth.getAccount().getUuid(), device.getId(), message.guid(), message.serverTimestamp()); @@ -348,7 +320,7 @@ public class WebSocketConnection implements MessageAvailabilityListener, Displac sendFutures[i] = CompletableFuture.completedFuture(null); } else { - sendFutures[i] = sendMessage(builder.build(), Optional.of(new StoredMessageInfo(message.guid(), message.serverTimestamp()))); + sendFutures[i] = sendMessage(envelope, Optional.of(new StoredMessageInfo(message.guid(), message.serverTimestamp()))); } }