mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-26 12:44:38 +00:00
Truncate message length based on utf8-byte size.
This commit is contained in:
@@ -92,6 +92,7 @@ import kotlinx.coroutines.launch
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import org.signal.core.util.ByteLimitInputFilter
|
||||
import org.signal.core.util.PendingIntentFlags
|
||||
import org.signal.core.util.Result
|
||||
import org.signal.core.util.ThreadUtil
|
||||
@@ -319,6 +320,7 @@ import org.thoughtcrime.securesms.util.MediaUtil
|
||||
import org.thoughtcrime.securesms.util.MessageConstraintsUtil
|
||||
import org.thoughtcrime.securesms.util.MessageConstraintsUtil.getEditMessageThresholdHours
|
||||
import org.thoughtcrime.securesms.util.MessageConstraintsUtil.isValidEditMessageSend
|
||||
import org.thoughtcrime.securesms.util.MessageUtil
|
||||
import org.thoughtcrime.securesms.util.PlayStoreUtil
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig
|
||||
import org.thoughtcrime.securesms.util.SignalLocalMetrics
|
||||
@@ -405,7 +407,7 @@ class ConversationFragment :
|
||||
}
|
||||
|
||||
private val disposables = LifecycleDisposable()
|
||||
private val binding by ViewBinderDelegate(V2ConversationFragmentBinding::bind) { _binding ->
|
||||
private val binding by ViewBinderDelegate(bindingFactory = V2ConversationFragmentBinding::bind, onBindingWillBeDestroyed = { _binding ->
|
||||
_binding.conversationInputPanel.embeddedTextEditor.apply {
|
||||
setOnEditorActionListener(null)
|
||||
setCursorPositionChangedListener(null)
|
||||
@@ -428,7 +430,7 @@ class ConversationFragment :
|
||||
_binding.conversationItemRecycler.adapter = null
|
||||
|
||||
textDraftSaveDebouncer.clear()
|
||||
}
|
||||
})
|
||||
|
||||
private val viewModel: ConversationViewModel by viewModel {
|
||||
ConversationViewModel(
|
||||
@@ -1013,6 +1015,7 @@ class ConversationFragment :
|
||||
setStylingChangedListener(composeTextEventsListener)
|
||||
setOnClickListener(composeTextEventsListener)
|
||||
onFocusChangeListener = composeTextEventsListener
|
||||
filters += ByteLimitInputFilter(MessageUtil.MAX_TOTAL_BODY_SIZE_BYTES)
|
||||
}
|
||||
|
||||
sendButton.apply {
|
||||
|
||||
@@ -31,6 +31,9 @@ import org.thoughtcrime.securesms.net.NotPushRegisteredException
|
||||
import org.thoughtcrime.securesms.net.SignalNetwork
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.service.AttachmentProgressService
|
||||
import org.thoughtcrime.securesms.transport.UndeliverableMessageException
|
||||
import org.thoughtcrime.securesms.util.MediaUtil
|
||||
import org.thoughtcrime.securesms.util.MessageUtil
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
import org.whispersystems.signalservice.api.attachment.AttachmentUploadResult
|
||||
@@ -137,6 +140,10 @@ class AttachmentUploadJob private constructor(
|
||||
|
||||
val databaseAttachment = SignalDatabase.attachments.getAttachment(attachmentId) ?: throw InvalidAttachmentException("Cannot find the specified attachment.")
|
||||
|
||||
if (MediaUtil.isLongTextType(databaseAttachment.contentType) && databaseAttachment.size > MessageUtil.MAX_TOTAL_BODY_SIZE_BYTES) {
|
||||
throw UndeliverableMessageException("Long text attachment is too long! Max size: ${MessageUtil.MAX_TOTAL_BODY_SIZE_BYTES} bytes, Actual size: ${databaseAttachment.size} bytes.")
|
||||
}
|
||||
|
||||
val timeSinceUpload = System.currentTimeMillis() - databaseAttachment.uploadTimestamp
|
||||
if (timeSinceUpload < UPLOAD_REUSE_THRESHOLD && !TextUtils.isEmpty(databaseAttachment.remoteLocation)) {
|
||||
Log.i(TAG, "We can re-use an already-uploaded file. It was uploaded $timeSinceUpload ms (${timeSinceUpload.milliseconds.inRoundedDays()} days) ago. Skipping.")
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
||||
import org.thoughtcrime.securesms.util.MessageUtil;
|
||||
import org.thoughtcrime.securesms.util.SignalLocalMetrics;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
@@ -60,6 +61,8 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okio.Utf8;
|
||||
|
||||
public class IndividualSendJob extends PushSendJob {
|
||||
|
||||
public static final String KEY = "PushMediaSendJob";
|
||||
@@ -251,6 +254,10 @@ public class IndividualSendJob extends PushSendJob {
|
||||
throw new UndeliverableMessageException("No destination address.");
|
||||
}
|
||||
|
||||
if (Utf8.size(message.getBody()) > MessageUtil.MAX_INLINE_BODY_SIZE_BYTES) {
|
||||
throw new UndeliverableMessageException("The total body size was greater than our limit of " + MessageUtil.MAX_INLINE_BODY_SIZE_BYTES + " bytes.");
|
||||
}
|
||||
|
||||
try {
|
||||
rotateSenderCertificateIfNecessary();
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.MessageUtil;
|
||||
import org.thoughtcrime.securesms.util.RecipientAccessList;
|
||||
import org.thoughtcrime.securesms.util.SignalLocalMetrics;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
@@ -73,6 +74,7 @@ import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okio.ByteString;
|
||||
import okio.Utf8;
|
||||
|
||||
public final class PushGroupSendJob extends PushSendJob {
|
||||
|
||||
@@ -266,6 +268,10 @@ public final class PushGroupSendJob extends PushSendJob {
|
||||
private List<SendMessageResult> deliver(OutgoingMessage message, @Nullable MessageRecord originalEditedMessage, @NonNull Recipient groupRecipient, @NonNull List<Recipient> destinations)
|
||||
throws IOException, UntrustedIdentityException, UndeliverableMessageException
|
||||
{
|
||||
if (Utf8.size(message.getBody()) >= MessageUtil.MAX_INLINE_BODY_SIZE_BYTES) {
|
||||
throw new UndeliverableMessageException("The total body size was greater than our limit of " + MessageUtil.MAX_INLINE_BODY_SIZE_BYTES + " bytes.");
|
||||
}
|
||||
|
||||
try {
|
||||
rotateSenderCertificateIfNecessary();
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import androidx.lifecycle.ViewModelProvider
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import org.signal.core.util.ByteLimitInputFilter
|
||||
import org.signal.core.util.EditTextUtil
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout
|
||||
@@ -38,6 +39,7 @@ import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.stories.Stories
|
||||
import org.thoughtcrime.securesms.util.MediaUtil
|
||||
import org.thoughtcrime.securesms.util.MessageUtil
|
||||
import org.thoughtcrime.securesms.util.ViewUtil
|
||||
import org.thoughtcrime.securesms.util.views.Stub
|
||||
import org.thoughtcrime.securesms.util.visible
|
||||
@@ -92,6 +94,7 @@ class AddMessageDialogFragment : KeyboardEntryDialogFragment(R.layout.v2_media_a
|
||||
|
||||
binding.content.addAMessageInput.setText(requireArguments().getCharSequence(ARG_INITIAL_TEXT))
|
||||
binding.content.addAMessageInput.addTextChangedListener { viewModel.setMessage(it) }
|
||||
binding.content.addAMessageInput.filters += ByteLimitInputFilter(MessageUtil.MAX_TOTAL_BODY_SIZE_BYTES)
|
||||
|
||||
binding.content.emojiToggle.setOnClickListener { onEmojiToggleClicked() }
|
||||
if (requireArguments().getBoolean(ARG_INITIAL_EMOJI_TOGGLE) && view is KeyboardAwareLinearLayout) {
|
||||
|
||||
@@ -51,7 +51,6 @@ import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
import org.thoughtcrime.securesms.util.MessageUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -116,7 +115,7 @@ public final class MultiShareSender {
|
||||
List<Contact> contacts = multiShareArgs.getSharedContacts();
|
||||
SlideDeck slideDeck = new SlideDeck(primarySlideDeck);
|
||||
|
||||
boolean needsSplit = message != null && Utf8.size(message) > MessageUtil.MAX_MESSAGE_SIZE_BYTES;
|
||||
boolean needsSplit = message != null && Utf8.size(message) > MessageUtil.MAX_INLINE_BODY_SIZE_BYTES;
|
||||
boolean hasMmsMedia = !multiShareArgs.getMedia().isEmpty() ||
|
||||
(multiShareArgs.getDataUri() != null && multiShareArgs.getDataUri() != Uri.EMPTY) ||
|
||||
multiShareArgs.getStickerLocator() != null ||
|
||||
|
||||
@@ -16,6 +16,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.transition.AutoTransition
|
||||
import androidx.transition.TransitionManager
|
||||
import org.signal.core.util.ByteLimitInputFilter
|
||||
import org.signal.core.util.dp
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.ComposeText
|
||||
@@ -34,6 +35,7 @@ import org.thoughtcrime.securesms.keyboard.emoji.toMappingModels
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.reactions.any.ReactWithAnyEmojiBottomSheetDialogFragment
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.MessageUtil
|
||||
import org.thoughtcrime.securesms.util.ViewUtil
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.MappingModel
|
||||
|
||||
@@ -86,6 +88,7 @@ class StoryReplyComposer @JvmOverloads constructor(
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
input.filters += ByteLimitInputFilter(MessageUtil.MAX_TOTAL_BODY_SIZE_BYTES)
|
||||
|
||||
anyReactionView.setOnClickListener {
|
||||
callback?.onPickAnyReactionClicked()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.thoughtcrime.securesms.util
|
||||
|
||||
import android.content.Context
|
||||
import org.signal.core.util.kibiBytes
|
||||
import org.signal.core.util.splitByByteLength
|
||||
import org.thoughtcrime.securesms.mms.TextSlide
|
||||
import org.thoughtcrime.securesms.providers.BlobProvider
|
||||
@@ -10,7 +11,13 @@ import java.util.Locale
|
||||
import java.util.Optional
|
||||
|
||||
object MessageUtil {
|
||||
const val MAX_MESSAGE_SIZE_BYTES: Int = 2000 // Technically 2048, but we'll play it a little safe
|
||||
/** The maximum size of an inlined text body we'll allow in a proto. Anything larger than this will need to be a long-text attachment. */
|
||||
@JvmField
|
||||
val MAX_INLINE_BODY_SIZE_BYTES: Int = 2.kibiBytes.bytes.toInt()
|
||||
|
||||
/** The maximum total message size we'll allow ourselves to send, even as a long text attachment. */
|
||||
@JvmField
|
||||
val MAX_TOTAL_BODY_SIZE_BYTES = 64.kibiBytes.bytes.toInt()
|
||||
|
||||
/**
|
||||
* @return If the message is longer than the allowed text size, this will return trimmed text with
|
||||
@@ -18,7 +25,7 @@ object MessageUtil {
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getSplitMessage(context: Context, rawText: String): SplitResult {
|
||||
val (trimmed, remainder) = rawText.splitByByteLength(MAX_MESSAGE_SIZE_BYTES)
|
||||
val (trimmed, remainder) = rawText.splitByByteLength(MAX_INLINE_BODY_SIZE_BYTES)
|
||||
|
||||
return if (remainder != null) {
|
||||
val textData = rawText.toByteArray()
|
||||
|
||||
Reference in New Issue
Block a user