Add support for addressing attachments within a message.

This commit is contained in:
Cody Henthorne
2024-06-14 11:35:52 -04:00
committed by Greyson Parrelli
parent 10922594b3
commit a2fc710261
35 changed files with 181 additions and 66 deletions

View File

@@ -862,7 +862,8 @@ public class SignalServiceMessageSender {
attachment.isGif(),
attachment.getCaption(),
attachment.getBlurHash(),
attachment.getUploadTimestamp());
attachment.getUploadTimestamp(),
attachment.getUuid());
}
public ResumableUploadSpec getResumableUploadSpec() throws IOException {
@@ -907,7 +908,8 @@ public class SignalServiceMessageSender {
attachment.isGif(),
attachment.getCaption(),
attachment.getBlurHash(),
attachment.getUploadTimestamp());
attachment.getUploadTimestamp(),
attachment.getUuid());
}
private SendMessageResult sendVerifiedSyncMessage(VerifiedMessage message)

View File

@@ -12,6 +12,9 @@ import org.whispersystems.signalservice.internal.push.http.ResumableUploadSpec;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.Optional;
import java.util.UUID;
import javax.annotation.Nullable;
public abstract class SignalServiceAttachment {
@@ -40,10 +43,6 @@ public abstract class SignalServiceAttachment {
return new Builder();
}
public static SignalServiceAttachmentStream emptyStream(String contentType) {
return new SignalServiceAttachmentStream(new ByteArrayInputStream(new byte[0]), contentType, 0, Optional.empty(), false, false, false, false, null, null);
}
public static class Builder {
private InputStream inputStream;
@@ -62,6 +61,7 @@ public abstract class SignalServiceAttachment {
private String blurHash;
private long uploadTimestamp;
private ResumableUploadSpec resumableUploadSpec;
private UUID uuid;
private Builder() {}
@@ -145,6 +145,11 @@ public abstract class SignalServiceAttachment {
return this;
}
public Builder withUuid(@Nullable UUID uuid) {
this.uuid = uuid;
return this;
}
public SignalServiceAttachmentStream build() {
if (inputStream == null) throw new IllegalArgumentException("Must specify stream!");
if (contentType == null) throw new IllegalArgumentException("No content type specified!");
@@ -166,7 +171,8 @@ public abstract class SignalServiceAttachment {
Optional.ofNullable(blurHash),
listener,
cancelationSignal,
Optional.ofNullable(resumableUploadSpec));
Optional.ofNullable(resumableUploadSpec),
uuid);
}
}

View File

@@ -9,6 +9,9 @@ package org.whispersystems.signalservice.api.messages;
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
import java.util.Optional;
import java.util.UUID;
import javax.annotation.Nullable;
/**
* Represents a received SignalServiceAttachment "handle." This
@@ -36,6 +39,7 @@ public class SignalServiceAttachmentPointer extends SignalServiceAttachment {
private final Optional<String> caption;
private final Optional<String> blurHash;
private final long uploadTimestamp;
private final UUID uuid;
public SignalServiceAttachmentPointer(int cdnNumber,
SignalServiceAttachmentRemoteId remoteId,
@@ -54,7 +58,8 @@ public class SignalServiceAttachmentPointer extends SignalServiceAttachment {
boolean gif,
Optional<String> caption,
Optional<String> blurHash,
long uploadTimestamp)
long uploadTimestamp,
@Nullable UUID uuid)
{
super(contentType);
this.cdnNumber = cdnNumber;
@@ -74,6 +79,7 @@ public class SignalServiceAttachmentPointer extends SignalServiceAttachment {
this.blurHash = blurHash;
this.uploadTimestamp = uploadTimestamp;
this.gif = gif;
this.uuid = uuid;
}
public int getCdnNumber() {
@@ -153,4 +159,8 @@ public class SignalServiceAttachmentPointer extends SignalServiceAttachment {
public long getUploadTimestamp() {
return uploadTimestamp;
}
public @Nullable UUID getUuid() {
return uuid;
}
}

View File

@@ -14,6 +14,9 @@ import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.util.Optional;
import java.util.UUID;
import javax.annotation.Nullable;
/**
* Represents a local SignalServiceAttachment to be sent.
@@ -36,6 +39,7 @@ public class SignalServiceAttachmentStream extends SignalServiceAttachment imple
private final Optional<String> caption;
private final Optional<String> blurHash;
private final Optional<ResumableUploadSpec> resumableUploadSpec;
private final UUID uuid;
public SignalServiceAttachmentStream(InputStream inputStream,
String contentType,
@@ -48,7 +52,7 @@ public class SignalServiceAttachmentStream extends SignalServiceAttachment imple
ProgressListener listener,
CancelationSignal cancelationSignal)
{
this(inputStream, contentType, length, fileName, voiceNote, borderless, gif, faststart, Optional.empty(), 0, 0, System.currentTimeMillis(), Optional.empty(), Optional.empty(), listener, cancelationSignal, Optional.empty());
this(inputStream, contentType, length, fileName, voiceNote, borderless, gif, faststart, Optional.empty(), 0, 0, System.currentTimeMillis(), Optional.empty(), Optional.empty(), listener, cancelationSignal, Optional.empty(), UUID.randomUUID());
}
public SignalServiceAttachmentStream(InputStream inputStream,
@@ -67,7 +71,8 @@ public class SignalServiceAttachmentStream extends SignalServiceAttachment imple
Optional<String> blurHash,
ProgressListener listener,
CancelationSignal cancelationSignal,
Optional<ResumableUploadSpec> resumableUploadSpec)
Optional<ResumableUploadSpec> resumableUploadSpec,
@Nullable UUID uuid)
{
super(contentType);
this.inputStream = inputStream;
@@ -86,6 +91,7 @@ public class SignalServiceAttachmentStream extends SignalServiceAttachment imple
this.blurHash = blurHash;
this.cancelationSignal = cancelationSignal;
this.resumableUploadSpec = resumableUploadSpec;
this.uuid = uuid;
}
@Override
@@ -162,6 +168,10 @@ public class SignalServiceAttachmentStream extends SignalServiceAttachment imple
return resumableUploadSpec;
}
public @Nullable UUID getUuid() {
return uuid;
}
@Override
public void close() throws IOException {
inputStream.close();

View File

@@ -106,11 +106,6 @@ class SignalServiceDataMessage private constructor(
return this
}
fun withAttachment(attachment: SignalServiceAttachment?): Builder {
attachment?.let { attachments.add(attachment) }
return this
}
fun withAttachments(attachments: List<SignalServiceAttachment>?): Builder {
attachments?.let { this.attachments.addAll(attachments) }
return this

View File

@@ -12,6 +12,7 @@ import org.signal.libsignal.protocol.InvalidMessageException;
import org.signal.libsignal.protocol.logging.Log;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentStream;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
@@ -62,7 +63,7 @@ public class DeviceContactsInputStream extends ChunkedInputStream {
InputStream avatarStream = new LimitedInputStream(in, avatarLength);
String avatarContentType = details.avatar.contentType;
avatar = Optional.of(new SignalServiceAttachmentStream(avatarStream, avatarContentType, avatarLength, Optional.empty(), false, false, false, false, null, null));
avatar = Optional.of(SignalServiceAttachment.newStreamBuilder().withStream(avatarStream).withContentType(avatarContentType).withLength(avatarLength).build());
}
if (details.verified != null) {

View File

@@ -35,8 +35,8 @@ public final class AttachmentPointerUtil {
((pointer.flags != null ? pointer.flags : 0) & FlagUtil.toBinaryFlag(AttachmentPointer.Flags.GIF.getValue())) != 0,
pointer.caption != null ? Optional.of(pointer.caption) : Optional.empty(),
pointer.blurHash != null ? Optional.of(pointer.blurHash) : Optional.empty(),
pointer.uploadTimestamp != null ? pointer.uploadTimestamp : 0);
pointer.uploadTimestamp != null ? pointer.uploadTimestamp : 0,
UuidUtil.fromByteStringOrNull(pointer.uuid));
}
public static AttachmentPointer createAttachmentPointer(SignalServiceAttachmentPointer attachment) {
@@ -104,6 +104,10 @@ public final class AttachmentPointerUtil {
builder.blurHash(attachment.getBlurHash().get());
}
if (attachment.getUuid() != null) {
builder.uuid(UuidUtil.toByteString(attachment.getUuid()));
}
return builder.build();
}
}

View File

@@ -8,6 +8,9 @@ import java.util.Optional;
import java.util.UUID;
import java.util.regex.Pattern;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import okio.ByteString;
public final class UuidUtil {
@@ -23,7 +26,7 @@ public final class UuidUtil {
return Optional.ofNullable(parseOrNull(uuid));
}
public static UUID parseOrNull(String uuid) {
public static UUID parseOrNull(@Nullable String uuid) {
return isUuid(uuid) ? parseOrThrow(uuid) : null;
}
@@ -47,7 +50,7 @@ public final class UuidUtil {
return uuid != null && UUID_PATTERN.matcher(uuid).matches();
}
public static byte[] toByteArray(UUID uuid) {
public static byte[] toByteArray(@Nonnull UUID uuid) {
ByteBuffer buffer = ByteBuffer.wrap(new byte[16]);
buffer.putLong(uuid.getMostSignificantBits());
buffer.putLong(uuid.getLeastSignificantBits());
@@ -55,7 +58,7 @@ public final class UuidUtil {
return buffer.array();
}
public static ByteString toByteString(UUID uuid) {
public static ByteString toByteString(@Nonnull UUID uuid) {
return ByteString.of(toByteArray(uuid));
}
@@ -63,7 +66,11 @@ public final class UuidUtil {
return parseOrThrow(bytes.toByteArray());
}
public static UUID fromByteStringOrNull(ByteString bytes) {
public static @Nullable UUID fromByteStringOrNull(@Nullable ByteString bytes) {
if (bytes == null) {
return null;
}
return parseOrNull(bytes.toByteArray());
}