Add support for versioned expiration timers.

Co-authored-by: Greyson Parrelli <greyson@signal.org>
This commit is contained in:
Cody Henthorne
2024-08-27 07:41:35 -04:00
committed by Nicholas Tinsley
parent 4152294b57
commit 1f196f74ff
43 changed files with 392 additions and 139 deletions

View File

@@ -158,7 +158,7 @@ object DataMessageProcessor {
when {
message.isInvalid -> handleInvalidMessage(context, senderRecipient.id, groupId, envelope.timestamp!!)
message.isEndSession -> insertResult = handleEndSessionMessage(context, senderRecipient.id, envelope, metadata)
message.isExpirationUpdate -> insertResult = handleExpirationUpdate(envelope, metadata, senderRecipient.id, threadRecipient.id, groupId, message.expireTimerDuration, receivedTime, false)
message.isExpirationUpdate -> insertResult = handleExpirationUpdate(envelope, metadata, senderRecipient, threadRecipient.id, groupId, message.expireTimerDuration, message.expireTimerVersion, receivedTime, false)
message.isStoryReaction -> insertResult = handleStoryReaction(context, envelope, metadata, message, senderRecipient.id, groupId)
message.reaction != null -> messageId = handleReaction(context, envelope, message, senderRecipient.id, earlyMessageCacheEntry)
message.hasRemoteDelete -> messageId = handleRemoteDelete(context, envelope, message, senderRecipient.id, earlyMessageCacheEntry)
@@ -321,10 +321,11 @@ object DataMessageProcessor {
private fun handleExpirationUpdate(
envelope: Envelope,
metadata: EnvelopeMetadata,
senderRecipientId: RecipientId,
senderRecipient: Recipient,
threadRecipientId: RecipientId,
groupId: GroupId.V2?,
expiresIn: Duration,
expireTimerVersion: Int?,
receivedTime: Long,
sideEffect: Boolean
): InsertResult? {
@@ -340,10 +341,15 @@ object DataMessageProcessor {
return null
}
if (expireTimerVersion != null && expireTimerVersion < senderRecipient.expireTimerVersion) {
log(envelope.timestamp!!, "Old expireTimerVersion. Received: $expireTimerVersion, Current: ${senderRecipient.expireTimerVersion}. Ignoring.")
return null
}
try {
val mediaMessage = IncomingMessage(
type = MessageType.EXPIRATION_UPDATE,
from = senderRecipientId,
from = senderRecipient.id,
sentTimeMillis = envelope.timestamp!! - if (sideEffect) 1 else 0,
serverTimeMillis = envelope.serverTimestamp!!,
receivedTimeMillis = receivedTime,
@@ -353,7 +359,13 @@ object DataMessageProcessor {
)
val insertResult: InsertResult? = SignalDatabase.messages.insertMessageInbox(mediaMessage, -1).orNull()
SignalDatabase.recipients.setExpireMessages(threadRecipientId, expiresIn.inWholeSeconds.toInt())
if (expireTimerVersion != null) {
SignalDatabase.recipients.setExpireMessages(threadRecipientId, expiresIn.inWholeSeconds.toInt(), expireTimerVersion)
} else {
// TODO [expireVersion] After unsupported builds expire, we can remove this branch
SignalDatabase.recipients.setExpireMessagesWithoutIncrementingVersion(threadRecipientId, expiresIn.inWholeSeconds.toInt())
}
if (insertResult != null) {
return insertResult
@@ -372,15 +384,16 @@ object DataMessageProcessor {
fun handlePossibleExpirationUpdate(
envelope: Envelope,
metadata: EnvelopeMetadata,
senderRecipientId: RecipientId,
senderRecipient: Recipient,
threadRecipient: Recipient,
groupId: GroupId.V2?,
expiresIn: Duration,
expireTimerVersion: Int?,
receivedTime: Long
) {
if (threadRecipient.expiresInSeconds.toLong() != expiresIn.inWholeSeconds) {
if (threadRecipient.expiresInSeconds.toLong() != expiresIn.inWholeSeconds || ((expireTimerVersion ?: -1) > threadRecipient.expireTimerVersion)) {
warn(envelope.timestamp!!, "Message expire time didn't match thread expire time. Handling timer update.")
handleExpirationUpdate(envelope, metadata, senderRecipientId, threadRecipient.id, groupId, expiresIn, receivedTime, true)
handleExpirationUpdate(envelope, metadata, senderRecipient, threadRecipient.id, groupId, expiresIn, expireTimerVersion, receivedTime, true)
}
}
@@ -741,7 +754,7 @@ object DataMessageProcessor {
threadRecipient = senderRecipient
}
handlePossibleExpirationUpdate(envelope, metadata, senderRecipient.id, threadRecipient, groupId, message.expireTimerDuration, receivedTime)
handlePossibleExpirationUpdate(envelope, metadata, senderRecipient, threadRecipient, groupId, message.expireTimerDuration, message.expireTimerVersion, receivedTime)
if (message.hasGroupContext) {
parentStoryId = GroupReply(storyMessageId.id)
@@ -892,7 +905,7 @@ object DataMessageProcessor {
val attachments: List<Attachment> = message.attachments.toPointersWithinLimit()
val messageRanges: BodyRangeList? = if (message.bodyRanges.isNotEmpty()) message.bodyRanges.asSequence().take(BODY_RANGE_PROCESSING_LIMIT).filter { it.mentionAci == null }.toList().toBodyRangeList() else null
handlePossibleExpirationUpdate(envelope, metadata, senderRecipient.id, threadRecipient, groupId, message.expireTimerDuration, receivedTime)
handlePossibleExpirationUpdate(envelope, metadata, senderRecipient, threadRecipient, groupId, message.expireTimerDuration, message.expireTimerVersion, receivedTime)
val mediaMessage = IncomingMessage(
type = MessageType.NORMAL,
@@ -972,7 +985,7 @@ object DataMessageProcessor {
val body = message.body ?: ""
handlePossibleExpirationUpdate(envelope, metadata, senderRecipient.id, threadRecipient, groupId, message.expireTimerDuration, receivedTime)
handlePossibleExpirationUpdate(envelope, metadata, senderRecipient, threadRecipient, groupId, message.expireTimerDuration, message.expireTimerVersion, receivedTime)
notifyTypingStoppedFromIncomingMessage(context, senderRecipient, threadRecipient.id, metadata.sourceDeviceId)

View File

@@ -353,6 +353,7 @@ object SyncMessageProcessor {
body = body,
timestamp = sent.timestamp!!,
expiresIn = targetMessage.expiresIn,
expireTimerVersion = targetMessage.expireTimerVersion,
isSecure = true,
bodyRanges = bodyRanges,
messageToEdit = targetMessage.id
@@ -366,6 +367,7 @@ object SyncMessageProcessor {
sentTimeMillis = sent.timestamp!!,
body = body,
expiresIn = targetMessage.expiresIn,
expireTimerVersion = targetMessage.expireTimerVersion,
isUrgent = true,
isSecure = true,
bodyRanges = bodyRanges,
@@ -429,6 +431,7 @@ object SyncMessageProcessor {
attachments = syncAttachments.ifEmpty { (targetMessage as? MmsMessageRecord)?.slideDeck?.asAttachments() ?: emptyList() },
timestamp = sent.timestamp!!,
expiresIn = targetMessage.expiresIn,
expireTimerVersion = targetMessage.expireTimerVersion,
viewOnce = viewOnce,
quote = quote,
contacts = sharedContacts,
@@ -676,13 +679,26 @@ object SyncMessageProcessor {
}
val recipient: Recipient = getSyncMessageDestination(sent)
val expirationUpdateMessage: OutgoingMessage = OutgoingMessage.expirationUpdateMessage(recipient, if (sideEffect) sent.timestamp!! - 1 else sent.timestamp!!, sent.message!!.expireTimerDuration.inWholeMilliseconds)
val threadId: Long = SignalDatabase.threads.getOrCreateThreadIdFor(recipient)
val messageId: Long = SignalDatabase.messages.insertMessageOutbox(expirationUpdateMessage, threadId, false, null)
val expirationUpdateMessage: OutgoingMessage = OutgoingMessage.expirationUpdateMessage(
threadRecipient = recipient,
sentTimeMillis = if (sideEffect) sent.timestamp!! - 1 else sent.timestamp!!,
expiresIn = sent.message!!.expireTimerDuration.inWholeMilliseconds,
expireTimerVersion = sent.message!!.expireTimerVersion ?: 1
)
SignalDatabase.messages.markAsSent(messageId, true)
SignalDatabase.recipients.setExpireMessages(recipient.id, sent.message!!.expireTimerDuration.inWholeSeconds.toInt())
if (sent.message?.expireTimerVersion == null) {
// TODO [expireVersion] After unsupported builds expire, we can remove this branch
SignalDatabase.recipients.setExpireMessagesWithoutIncrementingVersion(recipient.id, sent.message!!.expireTimerDuration.inWholeSeconds.toInt())
val messageId: Long = SignalDatabase.messages.insertMessageOutbox(expirationUpdateMessage, threadId, false, null)
SignalDatabase.messages.markAsSent(messageId, true)
} else if (sent.message!!.expireTimerVersion!! >= recipient.expireTimerVersion) {
SignalDatabase.recipients.setExpireMessages(recipient.id, sent.message!!.expireTimerDuration.inWholeSeconds.toInt(), sent.message!!.expireTimerVersion!!)
val messageId: Long = SignalDatabase.messages.insertMessageOutbox(expirationUpdateMessage, threadId, false, null)
SignalDatabase.messages.markAsSent(messageId, true)
} else {
warn(sent.timestamp!!, "[SynchronizeExpiration] Ignoring expire timer update with old version. Received: ${sent.message!!.expireTimerVersion}, Current: ${recipient.expireTimerVersion}")
}
return threadId
}
@@ -749,7 +765,7 @@ object SyncMessageProcessor {
isSecure = true
)
if (recipient.expiresInSeconds != dataMessage.expireTimerDuration.inWholeSeconds.toInt()) {
if (recipient.expiresInSeconds != dataMessage.expireTimerDuration.inWholeSeconds.toInt() || ((dataMessage.expireTimerVersion ?: -1) > recipient.expireTimerVersion)) {
handleSynchronizeSentExpirationUpdate(sent, sideEffect = true)
}
@@ -814,7 +830,7 @@ object SyncMessageProcessor {
isSecure = true
)
if (recipient.expiresInSeconds != dataMessage.expireTimerDuration.inWholeSeconds.toInt()) {
if (recipient.expiresInSeconds != dataMessage.expireTimerDuration.inWholeSeconds.toInt() || ((dataMessage.expireTimerVersion ?: -1) > recipient.expireTimerVersion)) {
handleSynchronizeSentExpirationUpdate(sent, sideEffect = true)
}
@@ -861,7 +877,7 @@ object SyncMessageProcessor {
val expiresInMillis = dataMessage.expireTimerDuration.inWholeMilliseconds
val bodyRanges = dataMessage.bodyRanges.filter { it.mentionAci == null }.toBodyRangeList()
if (recipient.expiresInSeconds != dataMessage.expireTimerDuration.inWholeSeconds.toInt()) {
if (recipient.expiresInSeconds != dataMessage.expireTimerDuration.inWholeSeconds.toInt() || ((dataMessage.expireTimerVersion ?: -1) > recipient.expireTimerVersion)) {
handleSynchronizeSentExpirationUpdate(sent, sideEffect = true)
}