Convert incoming/outgoing message entities to records
This commit is contained in:
		
							parent
							
								
									c4c5397b44
								
							
						
					
					
						commit
						3d875f1ce5
					
				| 
						 | 
					@ -182,16 +182,16 @@ public class MessageController {
 | 
				
			||||||
      senderType = SENDER_TYPE_UNIDENTIFIED;
 | 
					      senderType = SENDER_TYPE_UNIDENTIFIED;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (final IncomingMessage message : messages.getMessages()) {
 | 
					    for (final IncomingMessage message : messages.messages()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      int contentLength = 0;
 | 
					      int contentLength = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (!Util.isEmpty(message.getContent())) {
 | 
					      if (!Util.isEmpty(message.content())) {
 | 
				
			||||||
        contentLength += message.getContent().length();
 | 
					        contentLength += message.content().length();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      validateContentLength(contentLength, userAgent);
 | 
					      validateContentLength(contentLength, userAgent);
 | 
				
			||||||
      validateEnvelopeType(message.getType(), userAgent);
 | 
					      validateEnvelopeType(message.type(), userAgent);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
| 
						 | 
					@ -222,25 +222,25 @@ public class MessageController {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      DestinationDeviceValidator.validateCompleteDeviceList(destination.get(),
 | 
					      DestinationDeviceValidator.validateCompleteDeviceList(destination.get(),
 | 
				
			||||||
          messages.getMessages().stream().map(IncomingMessage::getDestinationDeviceId).collect(Collectors.toSet()),
 | 
					          messages.messages().stream().map(IncomingMessage::destinationDeviceId).collect(Collectors.toSet()),
 | 
				
			||||||
          excludedDeviceIds);
 | 
					          excludedDeviceIds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      DestinationDeviceValidator.validateRegistrationIds(destination.get(),
 | 
					      DestinationDeviceValidator.validateRegistrationIds(destination.get(),
 | 
				
			||||||
          messages.getMessages(),
 | 
					          messages.messages(),
 | 
				
			||||||
          IncomingMessage::getDestinationDeviceId,
 | 
					          IncomingMessage::destinationDeviceId,
 | 
				
			||||||
          IncomingMessage::getDestinationRegistrationId,
 | 
					          IncomingMessage::destinationRegistrationId,
 | 
				
			||||||
          destination.get().getPhoneNumberIdentifier().equals(destinationUuid));
 | 
					          destination.get().getPhoneNumberIdentifier().equals(destinationUuid));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      final List<Tag> tags = List.of(UserAgentTagUtil.getPlatformTag(userAgent),
 | 
					      final List<Tag> tags = List.of(UserAgentTagUtil.getPlatformTag(userAgent),
 | 
				
			||||||
          Tag.of(EPHEMERAL_TAG_NAME, String.valueOf(messages.isOnline())),
 | 
					          Tag.of(EPHEMERAL_TAG_NAME, String.valueOf(messages.online())),
 | 
				
			||||||
          Tag.of(SENDER_TYPE_TAG_NAME, senderType));
 | 
					          Tag.of(SENDER_TYPE_TAG_NAME, senderType));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      for (IncomingMessage incomingMessage : messages.getMessages()) {
 | 
					      for (IncomingMessage incomingMessage : messages.messages()) {
 | 
				
			||||||
        Optional<Device> destinationDevice = destination.get().getDevice(incomingMessage.getDestinationDeviceId());
 | 
					        Optional<Device> destinationDevice = destination.get().getDevice(incomingMessage.destinationDeviceId());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (destinationDevice.isPresent()) {
 | 
					        if (destinationDevice.isPresent()) {
 | 
				
			||||||
          Metrics.counter(SENT_MESSAGE_COUNTER_NAME, tags).increment();
 | 
					          Metrics.counter(SENT_MESSAGE_COUNTER_NAME, tags).increment();
 | 
				
			||||||
          sendMessage(source, destination.get(), destinationDevice.get(), destinationUuid, messages.getTimestamp(), messages.isOnline(), incomingMessage, userAgent);
 | 
					          sendMessage(source, destination.get(), destinationDevice.get(), destinationUuid, messages.timestamp(), messages.online(), incomingMessage, userAgent);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -438,9 +438,9 @@ public class MessageController {
 | 
				
			||||||
  private static long estimateMessageListSizeBytes(final OutgoingMessageEntityList messageList) {
 | 
					  private static long estimateMessageListSizeBytes(final OutgoingMessageEntityList messageList) {
 | 
				
			||||||
    long size = 0;
 | 
					    long size = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (final OutgoingMessageEntity message : messageList.getMessages()) {
 | 
					    for (final OutgoingMessageEntity message : messageList.messages()) {
 | 
				
			||||||
      size += message.getContent() == null      ? 0 : message.getContent().length;
 | 
					      size += message.content() == null      ? 0 : message.content().length;
 | 
				
			||||||
      size += Util.isEmpty(message.getSource()) ? 0 : message.getSource().length();
 | 
					      size += Util.isEmpty(message.source()) ? 0 : message.source().length();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return size;
 | 
					    return size;
 | 
				
			||||||
| 
						 | 
					@ -458,10 +458,10 @@ public class MessageController {
 | 
				
			||||||
          null);
 | 
					          null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (message.isPresent()) {
 | 
					      if (message.isPresent()) {
 | 
				
			||||||
        WebSocketConnection.recordMessageDeliveryDuration(message.get().getTimestamp(), auth.getAuthenticatedDevice());
 | 
					        WebSocketConnection.recordMessageDeliveryDuration(message.get().timestamp(), auth.getAuthenticatedDevice());
 | 
				
			||||||
        if (!Util.isEmpty(message.get().getSource())
 | 
					        if (!Util.isEmpty(message.get().source())
 | 
				
			||||||
            && message.get().getType() != Envelope.Type.SERVER_DELIVERY_RECEIPT_VALUE) {
 | 
					            && message.get().type() != Envelope.Type.SERVER_DELIVERY_RECEIPT_VALUE) {
 | 
				
			||||||
          receiptSender.sendReceipt(auth, message.get().getSourceUuid(), message.get().getTimestamp());
 | 
					          receiptSender.sendReceipt(auth, message.get().sourceUuid(), message.get().timestamp());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -523,10 +523,10 @@ public class MessageController {
 | 
				
			||||||
      Optional<byte[]> messageContent = getMessageContent(incomingMessage);
 | 
					      Optional<byte[]> messageContent = getMessageContent(incomingMessage);
 | 
				
			||||||
      Envelope.Builder messageBuilder = Envelope.newBuilder();
 | 
					      Envelope.Builder messageBuilder = Envelope.newBuilder();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      final Envelope.Type envelopeType = Envelope.Type.forNumber(incomingMessage.getType());
 | 
					      final Envelope.Type envelopeType = Envelope.Type.forNumber(incomingMessage.type());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (envelopeType == null) {
 | 
					      if (envelopeType == null) {
 | 
				
			||||||
        logger.warn("Received bad envelope type {} from {}", incomingMessage.getType(), userAgentString);
 | 
					        logger.warn("Received bad envelope type {} from {}", incomingMessage.type(), userAgentString);
 | 
				
			||||||
        throw new BadRequestException();
 | 
					        throw new BadRequestException();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -621,10 +621,10 @@ public class MessageController {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public static Optional<byte[]> getMessageContent(IncomingMessage message) {
 | 
					  public static Optional<byte[]> getMessageContent(IncomingMessage message) {
 | 
				
			||||||
    if (Util.isEmpty(message.getContent())) return Optional.empty();
 | 
					    if (Util.isEmpty(message.content())) return Optional.empty();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      return Optional.of(Base64.getDecoder().decode(message.getContent()));
 | 
					      return Optional.of(Base64.getDecoder().decode(message.content()));
 | 
				
			||||||
    } catch (IllegalArgumentException e) {
 | 
					    } catch (IllegalArgumentException e) {
 | 
				
			||||||
      logger.debug("Bad B64", e);
 | 
					      logger.debug("Bad B64", e);
 | 
				
			||||||
      return Optional.empty();
 | 
					      return Optional.empty();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,57 +4,6 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
package org.whispersystems.textsecuregcm.entities;
 | 
					package org.whispersystems.textsecuregcm.entities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.fasterxml.jackson.annotation.JsonCreator;
 | 
					public record IncomingMessage(int type, String destination, long destinationDeviceId, int destinationRegistrationId,
 | 
				
			||||||
import com.fasterxml.jackson.annotation.JsonProperty;
 | 
					                              String content) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
public class IncomingMessage {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @JsonProperty
 | 
					 | 
				
			||||||
  private final int type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @JsonProperty
 | 
					 | 
				
			||||||
  private final String destination;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @JsonProperty
 | 
					 | 
				
			||||||
  private final long destinationDeviceId;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @JsonProperty
 | 
					 | 
				
			||||||
  private final int destinationRegistrationId;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @JsonProperty
 | 
					 | 
				
			||||||
  private final String content;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @JsonCreator
 | 
					 | 
				
			||||||
  public IncomingMessage(
 | 
					 | 
				
			||||||
      @JsonProperty("id") final int type,
 | 
					 | 
				
			||||||
      @JsonProperty("destination") final String destination,
 | 
					 | 
				
			||||||
      @JsonProperty("destinationDeviceId") final long destinationDeviceId,
 | 
					 | 
				
			||||||
      @JsonProperty("destinationRegistrationId") final int destinationRegistrationId,
 | 
					 | 
				
			||||||
      @JsonProperty("content") final String content) {
 | 
					 | 
				
			||||||
    this.type = type;
 | 
					 | 
				
			||||||
    this.destination = destination;
 | 
					 | 
				
			||||||
    this.destinationDeviceId = destinationDeviceId;
 | 
					 | 
				
			||||||
    this.destinationRegistrationId = destinationRegistrationId;
 | 
					 | 
				
			||||||
    this.content = content;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public String getDestination() {
 | 
					 | 
				
			||||||
    return destination;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public int getType() {
 | 
					 | 
				
			||||||
    return type;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public long getDestinationDeviceId() {
 | 
					 | 
				
			||||||
    return destinationDeviceId;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public int getDestinationRegistrationId() {
 | 
					 | 
				
			||||||
    return destinationRegistrationId;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public String getContent() {
 | 
					 | 
				
			||||||
    return content;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,44 +4,9 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
package org.whispersystems.textsecuregcm.entities;
 | 
					package org.whispersystems.textsecuregcm.entities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.fasterxml.jackson.annotation.JsonCreator;
 | 
					 | 
				
			||||||
import com.fasterxml.jackson.annotation.JsonProperty;
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import javax.validation.Valid;
 | 
					import javax.validation.Valid;
 | 
				
			||||||
import javax.validation.constraints.NotNull;
 | 
					import javax.validation.constraints.NotNull;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class IncomingMessageList {
 | 
					public record IncomingMessageList(@NotNull @Valid List<@NotNull IncomingMessage> messages, boolean online, long timestamp) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
  @JsonProperty
 | 
					 | 
				
			||||||
  @NotNull
 | 
					 | 
				
			||||||
  @Valid
 | 
					 | 
				
			||||||
  private final List<@NotNull IncomingMessage> messages;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @JsonProperty
 | 
					 | 
				
			||||||
  private final long timestamp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @JsonProperty
 | 
					 | 
				
			||||||
  private final boolean online;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @JsonCreator
 | 
					 | 
				
			||||||
  public IncomingMessageList(
 | 
					 | 
				
			||||||
      @JsonProperty("messages") final List<@NotNull IncomingMessage> messages,
 | 
					 | 
				
			||||||
      @JsonProperty("online") final boolean online,
 | 
					 | 
				
			||||||
      @JsonProperty("timestamp") final long timestamp) {
 | 
					 | 
				
			||||||
    this.messages = messages;
 | 
					 | 
				
			||||||
    this.timestamp = timestamp;
 | 
					 | 
				
			||||||
    this.online = online;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public List<IncomingMessage> getMessages() {
 | 
					 | 
				
			||||||
    return messages;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public long getTimestamp() {
 | 
					 | 
				
			||||||
    return timestamp;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public boolean isOnline() {
 | 
					 | 
				
			||||||
    return online;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,89 +11,18 @@ import java.util.Arrays;
 | 
				
			||||||
import java.util.Objects;
 | 
					import java.util.Objects;
 | 
				
			||||||
import java.util.UUID;
 | 
					import java.util.UUID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class OutgoingMessageEntity {
 | 
					public record OutgoingMessageEntity(UUID guid, int type, long timestamp, String source, UUID sourceUuid,
 | 
				
			||||||
 | 
					                                    int sourceDevice, UUID destinationUuid, UUID updatedPni, byte[] content,
 | 
				
			||||||
  private final UUID guid;
 | 
					                                    long serverTimestamp) {
 | 
				
			||||||
  private final int type;
 | 
					 | 
				
			||||||
  private final long timestamp;
 | 
					 | 
				
			||||||
  private final String source;
 | 
					 | 
				
			||||||
  private final UUID sourceUuid;
 | 
					 | 
				
			||||||
  private final int sourceDevice;
 | 
					 | 
				
			||||||
  private final UUID destinationUuid;
 | 
					 | 
				
			||||||
  private final UUID updatedPni;
 | 
					 | 
				
			||||||
  private final byte[] content;
 | 
					 | 
				
			||||||
  private final long serverTimestamp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @JsonCreator
 | 
					 | 
				
			||||||
  public OutgoingMessageEntity(@JsonProperty("guid") final UUID guid,
 | 
					 | 
				
			||||||
      @JsonProperty("type") final int type,
 | 
					 | 
				
			||||||
      @JsonProperty("timestamp") final long timestamp,
 | 
					 | 
				
			||||||
      @JsonProperty("source") final String source,
 | 
					 | 
				
			||||||
      @JsonProperty("sourceUuid") final UUID sourceUuid,
 | 
					 | 
				
			||||||
      @JsonProperty("sourceDevice") final int sourceDevice,
 | 
					 | 
				
			||||||
      @JsonProperty("destinationUuid") final UUID destinationUuid,
 | 
					 | 
				
			||||||
      @JsonProperty("updatedPni") final UUID updatedPni,
 | 
					 | 
				
			||||||
      @JsonProperty("content") final byte[] content,
 | 
					 | 
				
			||||||
      @JsonProperty("serverTimestamp") final long serverTimestamp)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    this.guid            = guid;
 | 
					 | 
				
			||||||
    this.type            = type;
 | 
					 | 
				
			||||||
    this.timestamp       = timestamp;
 | 
					 | 
				
			||||||
    this.source          = source;
 | 
					 | 
				
			||||||
    this.sourceUuid      = sourceUuid;
 | 
					 | 
				
			||||||
    this.sourceDevice    = sourceDevice;
 | 
					 | 
				
			||||||
    this.destinationUuid = destinationUuid;
 | 
					 | 
				
			||||||
    this.updatedPni      = updatedPni;
 | 
					 | 
				
			||||||
    this.content         = content;
 | 
					 | 
				
			||||||
    this.serverTimestamp = serverTimestamp;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public UUID getGuid() {
 | 
					 | 
				
			||||||
    return guid;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public int getType() {
 | 
					 | 
				
			||||||
    return type;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public long getTimestamp() {
 | 
					 | 
				
			||||||
    return timestamp;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public String getSource() {
 | 
					 | 
				
			||||||
    return source;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public UUID getSourceUuid() {
 | 
					 | 
				
			||||||
    return sourceUuid;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public int getSourceDevice() {
 | 
					 | 
				
			||||||
    return sourceDevice;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public UUID getDestinationUuid() {
 | 
					 | 
				
			||||||
    return destinationUuid;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public UUID getUpdatedPni() {
 | 
					 | 
				
			||||||
    return updatedPni;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public byte[] getContent() {
 | 
					 | 
				
			||||||
    return content;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public long getServerTimestamp() {
 | 
					 | 
				
			||||||
    return serverTimestamp;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public boolean equals(final Object o) {
 | 
					  public boolean equals(final Object o) {
 | 
				
			||||||
    if (this == o)
 | 
					    if (this == o) {
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    if (o == null || getClass() != o.getClass())
 | 
					    }
 | 
				
			||||||
 | 
					    if (o == null || getClass() != o.getClass()) {
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    final OutgoingMessageEntity that = (OutgoingMessageEntity) o;
 | 
					    final OutgoingMessageEntity that = (OutgoingMessageEntity) o;
 | 
				
			||||||
    return type == that.type && timestamp == that.timestamp && sourceDevice == that.sourceDevice
 | 
					    return type == that.type && timestamp == that.timestamp && sourceDevice == that.sourceDevice
 | 
				
			||||||
        && serverTimestamp == that.serverTimestamp && guid.equals(that.guid) && Objects.equals(source, that.source)
 | 
					        && serverTimestamp == that.serverTimestamp && guid.equals(that.guid) && Objects.equals(source, that.source)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,30 +5,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package org.whispersystems.textsecuregcm.entities;
 | 
					package org.whispersystems.textsecuregcm.entities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.fasterxml.jackson.annotation.JsonProperty;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class OutgoingMessageEntityList {
 | 
					public record OutgoingMessageEntityList(List<OutgoingMessageEntity> messages, boolean more) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
  @JsonProperty
 | 
					 | 
				
			||||||
  private List<OutgoingMessageEntity> messages;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @JsonProperty
 | 
					 | 
				
			||||||
  private boolean more;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public OutgoingMessageEntityList() {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public OutgoingMessageEntityList(List<OutgoingMessageEntity> messages, boolean more) {
 | 
					 | 
				
			||||||
    this.messages = messages;
 | 
					 | 
				
			||||||
    this.more     = more;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public List<OutgoingMessageEntity> getMessages() {
 | 
					 | 
				
			||||||
    return messages;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public boolean hasMore() {
 | 
					 | 
				
			||||||
    return more;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,7 +17,6 @@ import org.slf4j.Logger;
 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
import org.whispersystems.textsecuregcm.controllers.AccountController;
 | 
					import org.whispersystems.textsecuregcm.controllers.AccountController;
 | 
				
			||||||
import org.whispersystems.textsecuregcm.controllers.MessageController;
 | 
					import org.whispersystems.textsecuregcm.controllers.MessageController;
 | 
				
			||||||
import org.whispersystems.textsecuregcm.util.DestinationDeviceValidator;
 | 
					 | 
				
			||||||
import org.whispersystems.textsecuregcm.controllers.MismatchedDevicesException;
 | 
					import org.whispersystems.textsecuregcm.controllers.MismatchedDevicesException;
 | 
				
			||||||
import org.whispersystems.textsecuregcm.controllers.StaleDevicesException;
 | 
					import org.whispersystems.textsecuregcm.controllers.StaleDevicesException;
 | 
				
			||||||
import org.whispersystems.textsecuregcm.entities.IncomingMessage;
 | 
					import org.whispersystems.textsecuregcm.entities.IncomingMessage;
 | 
				
			||||||
| 
						 | 
					@ -25,7 +24,7 @@ import org.whispersystems.textsecuregcm.entities.MessageProtos.Envelope;
 | 
				
			||||||
import org.whispersystems.textsecuregcm.entities.SignedPreKey;
 | 
					import org.whispersystems.textsecuregcm.entities.SignedPreKey;
 | 
				
			||||||
import org.whispersystems.textsecuregcm.push.MessageSender;
 | 
					import org.whispersystems.textsecuregcm.push.MessageSender;
 | 
				
			||||||
import org.whispersystems.textsecuregcm.push.NotPushRegisteredException;
 | 
					import org.whispersystems.textsecuregcm.push.NotPushRegisteredException;
 | 
				
			||||||
import org.whispersystems.textsecuregcm.util.Pair;
 | 
					import org.whispersystems.textsecuregcm.util.DestinationDeviceValidator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class ChangeNumberManager {
 | 
					public class ChangeNumberManager {
 | 
				
			||||||
  private static final Logger logger = LoggerFactory.getLogger(AccountController.class);
 | 
					  private static final Logger logger = LoggerFactory.getLogger(AccountController.class);
 | 
				
			||||||
| 
						 | 
					@ -55,14 +54,14 @@ public class ChangeNumberManager {
 | 
				
			||||||
      // Check that all except master ID are in device messages
 | 
					      // Check that all except master ID are in device messages
 | 
				
			||||||
      DestinationDeviceValidator.validateCompleteDeviceList(
 | 
					      DestinationDeviceValidator.validateCompleteDeviceList(
 | 
				
			||||||
          account,
 | 
					          account,
 | 
				
			||||||
          deviceMessages.stream().map(IncomingMessage::getDestinationDeviceId).collect(Collectors.toSet()),
 | 
					          deviceMessages.stream().map(IncomingMessage::destinationDeviceId).collect(Collectors.toSet()),
 | 
				
			||||||
          Set.of(Device.MASTER_ID));
 | 
					          Set.of(Device.MASTER_ID));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      DestinationDeviceValidator.validateRegistrationIds(
 | 
					      DestinationDeviceValidator.validateRegistrationIds(
 | 
				
			||||||
          account,
 | 
					          account,
 | 
				
			||||||
          deviceMessages,
 | 
					          deviceMessages,
 | 
				
			||||||
          IncomingMessage::getDestinationDeviceId,
 | 
					          IncomingMessage::destinationDeviceId,
 | 
				
			||||||
          IncomingMessage::getDestinationRegistrationId,
 | 
					          IncomingMessage::destinationRegistrationId,
 | 
				
			||||||
          false);
 | 
					          false);
 | 
				
			||||||
    } else if (!ObjectUtils.allNull(pniIdentityKey, deviceSignedPreKeys, deviceMessages, pniRegistrationIds)) {
 | 
					    } else if (!ObjectUtils.allNull(pniIdentityKey, deviceSignedPreKeys, deviceMessages, pniRegistrationIds)) {
 | 
				
			||||||
      throw new IllegalArgumentException("PNI identity key, signed pre-keys, device messages, and registration IDs must be all null or all non-null");
 | 
					      throw new IllegalArgumentException("PNI identity key, signed pre-keys, device messages, and registration IDs must be all null or all non-null");
 | 
				
			||||||
| 
						 | 
					@ -83,7 +82,7 @@ public class ChangeNumberManager {
 | 
				
			||||||
    // around the server crashed at/above this point.
 | 
					    // around the server crashed at/above this point.
 | 
				
			||||||
    if (deviceMessages != null) {
 | 
					    if (deviceMessages != null) {
 | 
				
			||||||
      deviceMessages.forEach(message ->
 | 
					      deviceMessages.forEach(message ->
 | 
				
			||||||
          sendMessageToSelf(updatedAccount, updatedAccount.getDevice(message.getDestinationDeviceId()), message));
 | 
					          sendMessageToSelf(updatedAccount, updatedAccount.getDevice(message.destinationDeviceId()), message));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return updatedAccount;
 | 
					    return updatedAccount;
 | 
				
			||||||
| 
						 | 
					@ -103,7 +102,7 @@ public class ChangeNumberManager {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      long serverTimestamp = System.currentTimeMillis();
 | 
					      long serverTimestamp = System.currentTimeMillis();
 | 
				
			||||||
      Envelope envelope = Envelope.newBuilder()
 | 
					      Envelope envelope = Envelope.newBuilder()
 | 
				
			||||||
          .setType(Envelope.Type.forNumber(message.getType()))
 | 
					          .setType(Envelope.Type.forNumber(message.type()))
 | 
				
			||||||
          .setTimestamp(serverTimestamp)
 | 
					          .setTimestamp(serverTimestamp)
 | 
				
			||||||
          .setServerTimestamp(serverTimestamp)
 | 
					          .setServerTimestamp(serverTimestamp)
 | 
				
			||||||
          .setDestinationUuid(sourceAndDestinationAccount.getUuid().toString())
 | 
					          .setDestinationUuid(sourceAndDestinationAccount.getUuid().toString())
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -310,45 +310,45 @@ public class WebSocketConnection implements MessageAvailabilityListener, Displac
 | 
				
			||||||
      final OutgoingMessageEntityList messages = messagesManager
 | 
					      final OutgoingMessageEntityList messages = messagesManager
 | 
				
			||||||
          .getMessagesForDevice(auth.getAccount().getUuid(), device.getId(), client.getUserAgent(), cachedMessagesOnly);
 | 
					          .getMessagesForDevice(auth.getAccount().getUuid(), device.getId(), client.getUserAgent(), cachedMessagesOnly);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      final CompletableFuture<?>[] sendFutures = new CompletableFuture[messages.getMessages().size()];
 | 
					      final CompletableFuture<?>[] sendFutures = new CompletableFuture[messages.messages().size()];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      for (int i = 0; i < messages.getMessages().size(); i++) {
 | 
					      for (int i = 0; i < messages.messages().size(); i++) {
 | 
				
			||||||
        final OutgoingMessageEntity message = messages.getMessages().get(i);
 | 
					        final OutgoingMessageEntity message = messages.messages().get(i);
 | 
				
			||||||
        final Envelope.Builder builder = Envelope.newBuilder()
 | 
					        final Envelope.Builder builder = Envelope.newBuilder()
 | 
				
			||||||
            .setType(Envelope.Type.forNumber(message.getType()))
 | 
					            .setType(Envelope.Type.forNumber(message.type()))
 | 
				
			||||||
            .setTimestamp(message.getTimestamp())
 | 
					            .setTimestamp(message.timestamp())
 | 
				
			||||||
            .setServerTimestamp(message.getServerTimestamp());
 | 
					            .setServerTimestamp(message.serverTimestamp());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!Util.isEmpty(message.getSource())) {
 | 
					        if (!Util.isEmpty(message.source())) {
 | 
				
			||||||
          builder.setSource(message.getSource())
 | 
					          builder.setSource(message.source())
 | 
				
			||||||
              .setSourceDevice(message.getSourceDevice());
 | 
					              .setSourceDevice(message.sourceDevice());
 | 
				
			||||||
          if (message.getSourceUuid() != null) {
 | 
					          if (message.sourceUuid() != null) {
 | 
				
			||||||
            builder.setSourceUuid(message.getSourceUuid().toString());
 | 
					            builder.setSourceUuid(message.sourceUuid().toString());
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (message.getContent() != null) {
 | 
					        if (message.content() != null) {
 | 
				
			||||||
          builder.setContent(ByteString.copyFrom(message.getContent()));
 | 
					          builder.setContent(ByteString.copyFrom(message.content()));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        builder.setDestinationUuid(message.getDestinationUuid().toString());
 | 
					        builder.setDestinationUuid(message.destinationUuid().toString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (message.getUpdatedPni() != null) {
 | 
					        if (message.updatedPni() != null) {
 | 
				
			||||||
          builder.setUpdatedPni(message.getUpdatedPni().toString());
 | 
					          builder.setUpdatedPni(message.updatedPni().toString());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        builder.setServerGuid(message.getGuid().toString());
 | 
					        builder.setServerGuid(message.guid().toString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        final Envelope envelope = builder.build();
 | 
					        final Envelope envelope = builder.build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (envelope.getSerializedSize() > MAX_DESKTOP_MESSAGE_SIZE && isDesktopClient) {
 | 
					        if (envelope.getSerializedSize() > MAX_DESKTOP_MESSAGE_SIZE && isDesktopClient) {
 | 
				
			||||||
          messagesManager.delete(auth.getAccount().getUuid(), device.getId(), message.getGuid(), message.getServerTimestamp());
 | 
					          messagesManager.delete(auth.getAccount().getUuid(), device.getId(), message.guid(), message.serverTimestamp());
 | 
				
			||||||
          discardedMessagesMeter.mark();
 | 
					          discardedMessagesMeter.mark();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          sendFutures[i] = CompletableFuture.completedFuture(null);
 | 
					          sendFutures[i] = CompletableFuture.completedFuture(null);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          sendFutures[i] = sendMessage(builder.build(), Optional.of(new StoredMessageInfo(message.getGuid(), message.getServerTimestamp())));
 | 
					          sendFutures[i] = sendMessage(builder.build(), Optional.of(new StoredMessageInfo(message.guid(), message.serverTimestamp())));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -357,7 +357,7 @@ public class WebSocketConnection implements MessageAvailabilityListener, Displac
 | 
				
			||||||
          .orTimeout(sendFuturesTimeoutMillis, TimeUnit.MILLISECONDS)
 | 
					          .orTimeout(sendFuturesTimeoutMillis, TimeUnit.MILLISECONDS)
 | 
				
			||||||
          .whenComplete((v, cause) -> {
 | 
					          .whenComplete((v, cause) -> {
 | 
				
			||||||
            if (cause == null) {
 | 
					            if (cause == null) {
 | 
				
			||||||
              if (messages.hasMore()) {
 | 
					              if (messages.more()) {
 | 
				
			||||||
                sendNextMessagePage(cachedMessagesOnly, queueClearedFuture);
 | 
					                sendNextMessagePage(cachedMessagesOnly, queueClearedFuture);
 | 
				
			||||||
              } else {
 | 
					              } else {
 | 
				
			||||||
                queueClearedFuture.complete(null);
 | 
					                queueClearedFuture.complete(null);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -391,19 +391,19 @@ class MessageControllerTest {
 | 
				
			||||||
            .accept(MediaType.APPLICATION_JSON_TYPE)
 | 
					            .accept(MediaType.APPLICATION_JSON_TYPE)
 | 
				
			||||||
            .get(OutgoingMessageEntityList.class);
 | 
					            .get(OutgoingMessageEntityList.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assertEquals(response.getMessages().size(), 2);
 | 
					    assertEquals(response.messages().size(), 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assertEquals(response.getMessages().get(0).getTimestamp(), timestampOne);
 | 
					    assertEquals(response.messages().get(0).timestamp(), timestampOne);
 | 
				
			||||||
    assertEquals(response.getMessages().get(1).getTimestamp(), timestampTwo);
 | 
					    assertEquals(response.messages().get(1).timestamp(), timestampTwo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assertEquals(response.getMessages().get(0).getGuid(), messageGuidOne);
 | 
					    assertEquals(response.messages().get(0).guid(), messageGuidOne);
 | 
				
			||||||
    assertNull(response.getMessages().get(1).getGuid());
 | 
					    assertNull(response.messages().get(1).guid());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assertEquals(response.getMessages().get(0).getSourceUuid(), sourceUuid);
 | 
					    assertEquals(response.messages().get(0).sourceUuid(), sourceUuid);
 | 
				
			||||||
    assertEquals(response.getMessages().get(1).getSourceUuid(), sourceUuid);
 | 
					    assertEquals(response.messages().get(1).sourceUuid(), sourceUuid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assertEquals(updatedPniOne, response.getMessages().get(0).getUpdatedPni());
 | 
					    assertEquals(updatedPniOne, response.messages().get(0).updatedPni());
 | 
				
			||||||
    assertNull(response.getMessages().get(1).getUpdatedPni());
 | 
					    assertNull(response.messages().get(1).updatedPni());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Test
 | 
					  @Test
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -116,8 +116,8 @@ public class ChangeNumberManagerTest {
 | 
				
			||||||
    final Map<Long, Integer> registrationIds = Map.of(1L, 17, 2L, 19);
 | 
					    final Map<Long, Integer> registrationIds = Map.of(1L, 17, 2L, 19);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    final IncomingMessage msg = mock(IncomingMessage.class);
 | 
					    final IncomingMessage msg = mock(IncomingMessage.class);
 | 
				
			||||||
    when(msg.getDestinationDeviceId()).thenReturn(2L);
 | 
					    when(msg.destinationDeviceId()).thenReturn(2L);
 | 
				
			||||||
    when(msg.getContent()).thenReturn(Base64.encodeBase64String(new byte[]{1}));
 | 
					    when(msg.content()).thenReturn(Base64.encodeBase64String(new byte[]{1}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    changeNumberManager.changeNumber(account, changedE164, pniIdentityKey, prekeys, List.of(msg), registrationIds);
 | 
					    changeNumberManager.changeNumber(account, changedE164, pniIdentityKey, prekeys, List.of(msg), registrationIds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -194,15 +194,15 @@ class MessagesDynamoDbTest {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private static void verify(OutgoingMessageEntity retrieved, MessageProtos.Envelope inserted) {
 | 
					  private static void verify(OutgoingMessageEntity retrieved, MessageProtos.Envelope inserted) {
 | 
				
			||||||
    assertThat(retrieved.getTimestamp()).isEqualTo(inserted.getTimestamp());
 | 
					    assertThat(retrieved.timestamp()).isEqualTo(inserted.getTimestamp());
 | 
				
			||||||
    assertThat(retrieved.getSource()).isEqualTo(inserted.hasSource() ? inserted.getSource() : null);
 | 
					    assertThat(retrieved.source()).isEqualTo(inserted.hasSource() ? inserted.getSource() : null);
 | 
				
			||||||
    assertThat(retrieved.getSourceUuid()).isEqualTo(inserted.hasSourceUuid() ? UUID.fromString(inserted.getSourceUuid()) : null);
 | 
					    assertThat(retrieved.sourceUuid()).isEqualTo(inserted.hasSourceUuid() ? UUID.fromString(inserted.getSourceUuid()) : null);
 | 
				
			||||||
    assertThat(retrieved.getSourceDevice()).isEqualTo(inserted.getSourceDevice());
 | 
					    assertThat(retrieved.sourceDevice()).isEqualTo(inserted.getSourceDevice());
 | 
				
			||||||
    assertThat(retrieved.getType()).isEqualTo(inserted.getType().getNumber());
 | 
					    assertThat(retrieved.type()).isEqualTo(inserted.getType().getNumber());
 | 
				
			||||||
    assertThat(retrieved.getContent()).isEqualTo(inserted.hasContent() ? inserted.getContent().toByteArray() : null);
 | 
					    assertThat(retrieved.content()).isEqualTo(inserted.hasContent() ? inserted.getContent().toByteArray() : null);
 | 
				
			||||||
    assertThat(retrieved.getServerTimestamp()).isEqualTo(inserted.getServerTimestamp());
 | 
					    assertThat(retrieved.serverTimestamp()).isEqualTo(inserted.getServerTimestamp());
 | 
				
			||||||
    assertThat(retrieved.getGuid()).isEqualTo(UUID.fromString(inserted.getServerGuid()));
 | 
					    assertThat(retrieved.guid()).isEqualTo(UUID.fromString(inserted.getServerGuid()));
 | 
				
			||||||
    assertThat(retrieved.getDestinationUuid()).isEqualTo(UUID.fromString(inserted.getDestinationUuid()));
 | 
					    assertThat(retrieved.destinationUuid()).isEqualTo(UUID.fromString(inserted.getDestinationUuid()));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private static VerifyMessage verify(MessageProtos.Envelope expected) {
 | 
					  private static VerifyMessage verify(MessageProtos.Envelope expected) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,7 +64,6 @@ import org.whispersystems.websocket.WebSocketClient;
 | 
				
			||||||
import org.whispersystems.websocket.auth.WebSocketAuthenticator.AuthenticationResult;
 | 
					import org.whispersystems.websocket.auth.WebSocketAuthenticator.AuthenticationResult;
 | 
				
			||||||
import org.whispersystems.websocket.messages.WebSocketResponseMessage;
 | 
					import org.whispersystems.websocket.messages.WebSocketResponseMessage;
 | 
				
			||||||
import org.whispersystems.websocket.session.WebSocketSessionContext;
 | 
					import org.whispersystems.websocket.session.WebSocketSessionContext;
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class WebSocketConnectionTest {
 | 
					class WebSocketConnectionTest {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -208,7 +207,7 @@ class WebSocketConnectionTest {
 | 
				
			||||||
    futures.get(0).completeExceptionally(new IOException());
 | 
					    futures.get(0).completeExceptionally(new IOException());
 | 
				
			||||||
    futures.get(2).completeExceptionally(new IOException());
 | 
					    futures.get(2).completeExceptionally(new IOException());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    verify(storedMessages, times(1)).delete(eq(accountUuid), eq(2L), eq(outgoingMessages.get(1).getGuid()), eq(outgoingMessages.get(1).getServerTimestamp()));
 | 
					    verify(storedMessages, times(1)).delete(eq(accountUuid), eq(2L), eq(outgoingMessages.get(1).guid()), eq(outgoingMessages.get(1).serverTimestamp()));
 | 
				
			||||||
    verify(receiptSender, times(1)).sendReceipt(eq(auth), eq(senderOneUuid), eq(2222L));
 | 
					    verify(receiptSender, times(1)).sendReceipt(eq(auth), eq(senderOneUuid), eq(2222L));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    connection.stop();
 | 
					    connection.stop();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue