Store attachments with a file extension

Taken from the filename if present, otherwise guessed from the contentType
This commit is contained in:
AsamK 2022-10-22 20:32:11 +02:00
parent 0084a2e722
commit e0c2f58e8d
3 changed files with 44 additions and 18 deletions

View file

@ -1,12 +1,15 @@
package org.asamk.signal.manager; package org.asamk.signal.manager;
import org.asamk.signal.manager.util.IOUtils; import org.asamk.signal.manager.util.IOUtils;
import org.asamk.signal.manager.util.MimeUtils;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Optional;
public class AttachmentStore { public class AttachmentStore {
@ -17,15 +20,23 @@ public class AttachmentStore {
} }
public void storeAttachmentPreview( public void storeAttachmentPreview(
final SignalServiceAttachmentRemoteId attachmentId, final AttachmentStorer storer final SignalServiceAttachmentPointer pointer, final AttachmentStorer storer
) throws IOException { ) throws IOException {
storeAttachment(getAttachmentPreviewFile(attachmentId), storer); storeAttachment(getAttachmentPreviewFile(pointer.getRemoteId(),
pointer.getFileName(),
Optional.ofNullable(pointer.getContentType())), storer);
} }
public void storeAttachment( public void storeAttachment(
final SignalServiceAttachmentRemoteId attachmentId, final AttachmentStorer storer final SignalServiceAttachmentPointer pointer, final AttachmentStorer storer
) throws IOException { ) throws IOException {
storeAttachment(getAttachmentFile(attachmentId), storer); storeAttachment(getAttachmentFile(pointer), storer);
}
public File getAttachmentFile(final SignalServiceAttachmentPointer pointer) {
return getAttachmentFile(pointer.getRemoteId(),
pointer.getFileName(),
Optional.ofNullable(pointer.getContentType()));
} }
private void storeAttachment(final File attachmentFile, final AttachmentStorer storer) throws IOException { private void storeAttachment(final File attachmentFile, final AttachmentStorer storer) throws IOException {
@ -35,12 +46,28 @@ public class AttachmentStore {
} }
} }
private File getAttachmentPreviewFile(SignalServiceAttachmentRemoteId attachmentId) { private File getAttachmentPreviewFile(
return new File(attachmentsPath, attachmentId.toString() + ".preview"); SignalServiceAttachmentRemoteId attachmentId, Optional<String> filename, Optional<String> contentType
) {
final var extension = getAttachmentExtension(filename, contentType);
return new File(attachmentsPath, attachmentId.toString() + extension + ".preview");
} }
public File getAttachmentFile(SignalServiceAttachmentRemoteId attachmentId) { private File getAttachmentFile(
return new File(attachmentsPath, attachmentId.toString()); SignalServiceAttachmentRemoteId attachmentId, Optional<String> filename, Optional<String> contentType
) {
final var extension = getAttachmentExtension(filename, contentType);
return new File(attachmentsPath, attachmentId.toString() + extension);
}
private static String getAttachmentExtension(
final Optional<String> filename, final Optional<String> contentType
) {
return filename.filter(f -> f.contains("."))
.map(f -> f.substring(f.lastIndexOf(".") + 1))
.or(() -> contentType.flatMap(MimeUtils::guessExtensionFromMimeType))
.map(ext -> "." + ext)
.orElse("");
} }
private void createAttachmentsDir() throws IOException { private void createAttachmentsDir() throws IOException {

View file

@ -6,7 +6,7 @@ import org.asamk.signal.manager.helper.RecipientAddressResolver;
import org.asamk.signal.manager.storage.recipients.RecipientResolver; import org.asamk.signal.manager.storage.recipients.RecipientResolver;
import org.signal.libsignal.metadata.ProtocolException; import org.signal.libsignal.metadata.ProtocolException;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment; import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
import org.whispersystems.signalservice.api.messages.SignalServiceContent; import org.whispersystems.signalservice.api.messages.SignalServiceContent;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope; import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
@ -281,8 +281,9 @@ public record MessageEnvelope(
static Attachment from(SignalServiceAttachment attachment, AttachmentFileProvider fileProvider) { static Attachment from(SignalServiceAttachment attachment, AttachmentFileProvider fileProvider) {
if (attachment.isPointer()) { if (attachment.isPointer()) {
final var a = attachment.asPointer(); final var a = attachment.asPointer();
return new Attachment(Optional.of(a.getRemoteId().toString()), final var attachmentFile = fileProvider.getFile(a);
Optional.of(fileProvider.getFile(a.getRemoteId())), return new Attachment(Optional.of(attachmentFile.getName()),
Optional.of(attachmentFile),
a.getFileName(), a.getFileName(),
a.getContentType(), a.getContentType(),
a.getUploadTimestamp() == 0 ? Optional.empty() : Optional.of(a.getUploadTimestamp()), a.getUploadTimestamp() == 0 ? Optional.empty() : Optional.of(a.getUploadTimestamp()),
@ -918,6 +919,6 @@ public record MessageEnvelope(
public interface AttachmentFileProvider { public interface AttachmentFileProvider {
File getFile(SignalServiceAttachmentRemoteId attachmentRemoteId); File getFile(SignalServiceAttachmentPointer pointer);
} }
} }

View file

@ -11,7 +11,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment; import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentStream; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentStream;
import org.whispersystems.signalservice.api.push.exceptions.MissingConfigurationException; import org.whispersystems.signalservice.api.push.exceptions.MissingConfigurationException;
@ -35,8 +34,8 @@ public class AttachmentHelper {
this.attachmentStore = context.getAttachmentStore(); this.attachmentStore = context.getAttachmentStore();
} }
public File getAttachmentFile(SignalServiceAttachmentRemoteId attachmentId) { public File getAttachmentFile(SignalServiceAttachmentPointer pointer) {
return attachmentStore.getAttachmentFile(attachmentId); return attachmentStore.getAttachmentFile(pointer);
} }
public List<SignalServiceAttachment> uploadAttachments(final List<String> attachments) throws AttachmentInvalidException, IOException { public List<SignalServiceAttachment> uploadAttachments(final List<String> attachments) throws AttachmentInvalidException, IOException {
@ -69,7 +68,7 @@ public class AttachmentHelper {
if (pointer.getPreview().isPresent()) { if (pointer.getPreview().isPresent()) {
final var preview = pointer.getPreview().get(); final var preview = pointer.getPreview().get();
try { try {
attachmentStore.storeAttachmentPreview(pointer.getRemoteId(), attachmentStore.storeAttachmentPreview(pointer,
outputStream -> outputStream.write(preview, 0, preview.length)); outputStream -> outputStream.write(preview, 0, preview.length));
} catch (IOException e) { } catch (IOException e) {
logger.warn("Failed to download attachment preview, ignoring: {}", e.getMessage()); logger.warn("Failed to download attachment preview, ignoring: {}", e.getMessage());
@ -77,8 +76,7 @@ public class AttachmentHelper {
} }
try { try {
attachmentStore.storeAttachment(pointer.getRemoteId(), attachmentStore.storeAttachment(pointer, outputStream -> this.retrieveAttachment(pointer, outputStream));
outputStream -> this.retrieveAttachment(pointer, outputStream));
} catch (IOException e) { } catch (IOException e) {
logger.warn("Failed to download attachment ({}), ignoring: {}", pointer.getRemoteId(), e.getMessage()); logger.warn("Failed to download attachment ({}), ignoring: {}", pointer.getRemoteId(), e.getMessage());
} }