From 5321f8124a9edfa4bc43006d64957f3b48d03c63 Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Mon, 18 May 2026 15:37:22 -0400 Subject: [PATCH] Add additional download checks to long message text attachments. --- .../securesms/jobs/AttachmentDownloadJob.kt | 6 ++++++ .../org/thoughtcrime/securesms/util/AttachmentUtil.kt | 2 +- .../thoughtcrime/securesms/util/AttachmentUtilTest.kt | 10 ++++++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.kt index 9e4c92d0c2..d136b62177 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.kt @@ -38,6 +38,8 @@ import org.thoughtcrime.securesms.notifications.v2.ConversationId.Companion.forC import org.thoughtcrime.securesms.s3.S3 import org.thoughtcrime.securesms.transport.RetryLaterException import org.thoughtcrime.securesms.util.AttachmentUtil +import org.thoughtcrime.securesms.util.MediaUtil +import org.thoughtcrime.securesms.util.MessageUtil import org.thoughtcrime.securesms.util.RemoteConfig import org.whispersystems.signalservice.api.crypto.AttachmentCipherInputStream.IntegrityCheck import org.whispersystems.signalservice.api.crypto.AttachmentCipherStreamUtil @@ -301,6 +303,10 @@ class AttachmentDownloadJob private constructor( throw MmsException("[$attachmentId] Attachment too large, failing download") } + if (MediaUtil.isLongTextType(attachment.contentType) && attachment.size > MessageUtil.MAX_TOTAL_BODY_SIZE_BYTES) { + throw InvalidAttachmentException("[$attachmentId] Long-text attachment exceeds ${MessageUtil.MAX_TOTAL_BODY_SIZE_BYTES} byte cap, declared size: ${attachment.size}") + } + val pointer = createAttachmentPointer(attachment) val progressListener = object : SignalServiceAttachment.ProgressListener { diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/AttachmentUtil.kt b/app/src/main/java/org/thoughtcrime/securesms/util/AttachmentUtil.kt index 629d139c6f..e00447db58 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/AttachmentUtil.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/AttachmentUtil.kt @@ -73,7 +73,7 @@ object AttachmentUtil { val contentType = attachment.contentType return when { - MediaUtil.isLongTextType(contentType) -> true + MediaUtil.isLongTextType(contentType) -> attachment.size <= MessageUtil.MAX_TOTAL_BODY_SIZE_BYTES attachment.isSticker -> ciphertextSize <= SMALL_ATTACHMENT_SIZE || allowedForType(allowedTypes, "image", "sticker") attachment.voiceNote -> ciphertextSize <= SMALL_ATTACHMENT_SIZE || allowedForType(allowedTypes, "audio", "voice message") attachment.videoGif -> allowedForType(allowedTypes, "image", "video gif") diff --git a/app/src/test/java/org/thoughtcrime/securesms/util/AttachmentUtilTest.kt b/app/src/test/java/org/thoughtcrime/securesms/util/AttachmentUtilTest.kt index 141133fd8e..af5e212d15 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/util/AttachmentUtilTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/util/AttachmentUtilTest.kt @@ -210,11 +210,17 @@ class AttachmentUtilTest { } @Test - fun `long text always permitted`() { - val attachment = attachment(contentType = "text/x-signal-plain") + fun `long text within 64 KiB cap permitted`() { + val attachment = attachment(size = MessageUtil.MAX_TOTAL_BODY_SIZE_BYTES.toLong(), contentType = "text/x-signal-plain") assertTrue(AttachmentUtil.isAutoDownloadPermitted(context, attachment)) } + @Test + fun `long text exceeding 64 KiB cap rejected`() { + val attachment = attachment(size = MessageUtil.MAX_TOTAL_BODY_SIZE_BYTES.toLong() + 1, contentType = "text/x-signal-plain") + assertFalse(AttachmentUtil.isAutoDownloadPermitted(context, attachment)) + } + @Test fun `small sticker always permitted regardless of allowed types or in-call`() { val attachment = attachment(size = 50L * 1024, isSticker = true, contentType = "image/webp")