Update SignalService.proto to match shared one.

This commit is contained in:
Greyson Parrelli
2026-03-26 09:37:44 -04:00
committed by Alex Hart
parent 5ae51f844e
commit f04a0533cb
22 changed files with 413 additions and 345 deletions

View File

@@ -316,7 +316,7 @@ class DataMessageProcessorTest_polls {
private fun insertPoll(allowMultiple: Boolean = true): Long { private fun insertPoll(allowMultiple: Boolean = true): Long {
val envelope = MessageContentFuzzer.envelope(100) val envelope = MessageContentFuzzer.envelope(100)
val pollMessage = IncomingMessage(type = MessageType.NORMAL, from = alice.id, sentTimeMillis = envelope.timestamp!!, serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = 0, groupId = groupId) val pollMessage = IncomingMessage(type = MessageType.NORMAL, from = alice.id, sentTimeMillis = envelope.clientTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = 0, groupId = groupId)
val messageId = SignalDatabase.messages.insertMessageInbox(pollMessage).get() val messageId = SignalDatabase.messages.insertMessageInbox(pollMessage).get()
SignalDatabase.polls.insertPoll("question?", allowMultiple, listOf("a", "b", "c"), alice.id.toLong(), messageId.messageId) SignalDatabase.polls.insertPoll("question?", allowMultiple, listOf("a", "b", "c"), alice.id.toLong(), messageId.messageId)
return messageId.messageId return messageId.messageId

View File

@@ -43,7 +43,7 @@ object MessageContentFuzzer {
*/ */
fun envelope(timestamp: Long, serverGuid: UUID = UUID.randomUUID()): Envelope { fun envelope(timestamp: Long, serverGuid: UUID = UUID.randomUUID()): Envelope {
return Envelope.Builder() return Envelope.Builder()
.timestamp(timestamp) .clientTimestamp(timestamp)
.serverTimestamp(timestamp + 5) .serverTimestamp(timestamp + 5)
.serverGuidBinary(serverGuid.toByteArray().toByteString()) .serverGuidBinary(serverGuid.toByteArray().toByteString())
.build() .build()
@@ -292,7 +292,7 @@ object MessageContentFuzzer {
body = string() body = string()
val quoted = quoteAble.random(random) val quoted = quoteAble.random(random)
quote = DataMessage.Quote.Builder().buildWith { quote = DataMessage.Quote.Builder().buildWith {
id = quoted.envelope.timestamp id = quoted.envelope.clientTimestamp
authorAciBinary = quoted.metadata.sourceServiceId.toByteString() authorAciBinary = quoted.metadata.sourceServiceId.toByteString()
text = quoted.content.dataMessage?.body text = quoted.content.dataMessage?.body
attachments(quoted.content.dataMessage?.attachments ?: emptyList()) attachments(quoted.content.dataMessage?.attachments ?: emptyList())
@@ -304,7 +304,7 @@ object MessageContentFuzzer {
if (random.nextFloat() < 0.1 && quoteAble.isNotEmpty()) { if (random.nextFloat() < 0.1 && quoteAble.isNotEmpty()) {
val quoted = quoteAble.random(random) val quoted = quoteAble.random(random)
quote = DataMessage.Quote.Builder().buildWith { quote = DataMessage.Quote.Builder().buildWith {
id = random.nextLong(quoted.envelope.timestamp!! - 1000000, quoted.envelope.timestamp!!) id = random.nextLong(quoted.envelope.clientTimestamp!! - 1000000, quoted.envelope.clientTimestamp!!)
authorAciBinary = quoted.metadata.sourceServiceId.toByteString() authorAciBinary = quoted.metadata.sourceServiceId.toByteString()
text = quoted.content.dataMessage?.body text = quoted.content.dataMessage?.body
} }
@@ -333,7 +333,7 @@ object MessageContentFuzzer {
emoji = emojis.random(random) emoji = emojis.random(random)
remove = false remove = false
targetAuthorAciBinary = reactTo.metadata.sourceServiceId.toByteString() targetAuthorAciBinary = reactTo.metadata.sourceServiceId.toByteString()
targetSentTimestamp = reactTo.envelope.timestamp targetSentTimestamp = reactTo.envelope.clientTimestamp
} }
} }
} }

View File

@@ -70,8 +70,8 @@ object Generator {
val serverGuid = UUID.randomUUID() val serverGuid = UUID.randomUUID()
return Envelope.Builder() return Envelope.Builder()
.type(Envelope.Type.fromValue(this.type)) .type(Envelope.Type.fromValue(this.type))
.sourceDevice(1) .sourceDeviceId(1)
.timestamp(timestamp) .clientTimestamp(timestamp)
.serverTimestamp(timestamp + 1) .serverTimestamp(timestamp + 1)
.destinationServiceId(destination.toString()) .destinationServiceId(destination.toString())
.destinationServiceIdBinary(destination.toByteString()) .destinationServiceIdBinary(destination.toByteString())

View File

@@ -67,9 +67,9 @@ class PushProcessMessageJobMigration : JobMigration(10) {
val envelope = Envelope.Builder() val envelope = Envelope.Builder()
.sourceServiceId(sourceServiceId.toString()) .sourceServiceId(sourceServiceId.toString())
.sourceDevice(proto.metadata!!.senderDevice) .sourceDeviceId(proto.metadata!!.senderDevice)
.destinationServiceId(destinationServiceId.toString()) .destinationServiceId(destinationServiceId.toString())
.timestamp(proto.metadata!!.timestamp) .clientTimestamp(proto.metadata!!.timestamp)
.serverGuid(proto.metadata!!.serverGuid) .serverGuid(proto.metadata!!.serverGuid)
.serverTimestamp(proto.metadata!!.serverReceivedTimestamp) .serverTimestamp(proto.metadata!!.serverReceivedTimestamp)

View File

@@ -155,7 +155,7 @@ class PushProcessMessageJob private constructor(
try { try {
messageProcessor.process(result.envelope, result.content, result.metadata, result.serverDeliveredTimestamp, localMetric = localReceiveMetric, batchCache = batchCache) messageProcessor.process(result.envelope, result.content, result.metadata, result.serverDeliveredTimestamp, localMetric = localReceiveMetric, batchCache = batchCache)
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Failed to process message with timestamp ${result.envelope.timestamp}. Dropping.", e) Log.e(TAG, "Failed to process message with timestamp ${result.envelope.clientTimestamp}. Dropping.", e)
} }
null null
} }

View File

@@ -41,15 +41,15 @@ object CallMessageProcessor {
if (metadata.destinationServiceId is ServiceId.PNI) { if (metadata.destinationServiceId is ServiceId.PNI) {
if (RecipientUtil.isCallRequestAccepted(senderRecipient) && callMessage.offer != null) { if (RecipientUtil.isCallRequestAccepted(senderRecipient) && callMessage.offer != null) {
log(envelope.timestamp!!, "Received call offer message at our PNI from trusted sender, responding with profile and pni signature") log(envelope.clientTimestamp!!, "Received call offer message at our PNI from trusted sender, responding with profile and pni signature")
RecipientUtil.shareProfileIfFirstSecureMessage(senderRecipient) RecipientUtil.shareProfileIfFirstSecureMessage(senderRecipient)
ProfileKeySendJob.create(senderRecipient, false)?.let { AppDependencies.jobManager.add(it) } ProfileKeySendJob.create(senderRecipient, false)?.let { AppDependencies.jobManager.add(it) }
} }
if (callMessage.offer != null) { if (callMessage.offer != null) {
log(envelope.timestamp!!, "Call message at our PNI is an offer, continuing.") log(envelope.clientTimestamp!!, "Call message at our PNI is an offer, continuing.")
} else { } else {
log(envelope.timestamp!!, "Call message at our PNI is not an offer, ignoring.") log(envelope.clientTimestamp!!, "Call message at our PNI is not an offer, ignoring.")
return return
} }
} }
@@ -65,12 +65,12 @@ object CallMessageProcessor {
} }
private fun handleCallOfferMessage(envelope: Envelope, metadata: EnvelopeMetadata, offer: Offer, senderRecipientId: RecipientId, serverDeliveredTimestamp: Long) { private fun handleCallOfferMessage(envelope: Envelope, metadata: EnvelopeMetadata, offer: Offer, senderRecipientId: RecipientId, serverDeliveredTimestamp: Long) {
log(envelope.timestamp!!, "handleCallOfferMessage...") log(envelope.clientTimestamp!!, "handleCallOfferMessage...")
val offerId = if (offer.id != null && offer.type != null && offer.opaque != null) { val offerId = if (offer.id != null && offer.type != null && offer.opaque != null) {
offer.id!! offer.id!!
} else { } else {
warn(envelope.timestamp!!, "Invalid offer, missing id, type, or opaque") warn(envelope.clientTimestamp!!, "Invalid offer, missing id, type, or opaque")
return return
} }
@@ -96,12 +96,12 @@ object CallMessageProcessor {
answer: CallMessage.Answer, answer: CallMessage.Answer,
senderRecipientId: RecipientId senderRecipientId: RecipientId
) { ) {
log(envelope.timestamp!!, "handleCallAnswerMessage...") log(envelope.clientTimestamp!!, "handleCallAnswerMessage...")
val answerId = if (answer.id != null && answer.opaque != null) { val answerId = if (answer.id != null && answer.opaque != null) {
answer.id!! answer.id!!
} else { } else {
warn(envelope.timestamp!!, "Invalid answer, missing id or opaque") warn(envelope.clientTimestamp!!, "Invalid answer, missing id or opaque")
return return
} }
@@ -122,7 +122,7 @@ object CallMessageProcessor {
iceUpdateList: List<CallMessage.IceUpdate>, iceUpdateList: List<CallMessage.IceUpdate>,
senderRecipientId: RecipientId senderRecipientId: RecipientId
) { ) {
log(envelope.timestamp!!, "handleCallIceUpdateMessage... " + iceUpdateList.size) log(envelope.clientTimestamp!!, "handleCallIceUpdateMessage... " + iceUpdateList.size)
val iceCandidates: MutableList<ByteArray> = ArrayList(iceUpdateList.size) val iceCandidates: MutableList<ByteArray> = ArrayList(iceUpdateList.size)
var callId: Long = -1 var callId: Long = -1
@@ -142,7 +142,7 @@ object CallMessageProcessor {
iceCandidates iceCandidates
) )
} else { } else {
warn(envelope.timestamp!!, "Invalid ice updates, all missing opaque and/or call id") warn(envelope.clientTimestamp!!, "Invalid ice updates, all missing opaque and/or call id")
} }
} }
@@ -152,12 +152,12 @@ object CallMessageProcessor {
hangup: CallMessage.Hangup?, hangup: CallMessage.Hangup?,
senderRecipientId: RecipientId senderRecipientId: RecipientId
) { ) {
log(envelope.timestamp!!, "handleCallHangupMessage") log(envelope.clientTimestamp!!, "handleCallHangupMessage")
val (hangupId: Long, hangupDeviceId: Int?) = if (hangup?.id != null) { val (hangupId: Long, hangupDeviceId: Int?) = if (hangup?.id != null) {
hangup.id!! to hangup.deviceId hangup.id!! to hangup.deviceId
} else { } else {
warn(envelope.timestamp!!, "Invalid hangup, null message or missing id/deviceId") warn(envelope.clientTimestamp!!, "Invalid hangup, null message or missing id/deviceId")
return return
} }
@@ -170,12 +170,12 @@ object CallMessageProcessor {
} }
private fun handleCallBusyMessage(envelope: Envelope, metadata: EnvelopeMetadata, busy: CallMessage.Busy, senderRecipientId: RecipientId) { private fun handleCallBusyMessage(envelope: Envelope, metadata: EnvelopeMetadata, busy: CallMessage.Busy, senderRecipientId: RecipientId) {
log(envelope.timestamp!!, "handleCallBusyMessage") log(envelope.clientTimestamp!!, "handleCallBusyMessage")
val busyId = if (busy.id != null) { val busyId = if (busy.id != null) {
busy.id!! busy.id!!
} else { } else {
warn(envelope.timestamp!!, "Invalid busy, missing call id") warn(envelope.clientTimestamp!!, "Invalid busy, missing call id")
return return
} }
@@ -184,12 +184,12 @@ object CallMessageProcessor {
} }
private fun handleCallOpaqueMessage(envelope: Envelope, metadata: EnvelopeMetadata, opaque: Opaque, senderServiceId: ServiceId, serverDeliveredTimestamp: Long) { private fun handleCallOpaqueMessage(envelope: Envelope, metadata: EnvelopeMetadata, opaque: Opaque, senderServiceId: ServiceId, serverDeliveredTimestamp: Long) {
log(envelope.timestamp!!, "handleCallOpaqueMessage") log(envelope.clientTimestamp!!, "handleCallOpaqueMessage")
val data = if (opaque.data_ != null) { val data = if (opaque.data_ != null) {
opaque.data_!!.toByteArray() opaque.data_!!.toByteArray()
} else { } else {
warn(envelope.timestamp!!, "Invalid opaque message, null data") warn(envelope.clientTimestamp!!, "Invalid opaque message, null data")
return return
} }

View File

@@ -149,7 +149,7 @@ object DataMessageProcessor {
SignalTrace.beginSection("DataMessageProcessor#gv2PreProcessing") SignalTrace.beginSection("DataMessageProcessor#gv2PreProcessing")
groupProcessResult = MessageContentProcessor.handleGv2PreProcessing( groupProcessResult = MessageContentProcessor.handleGv2PreProcessing(
context = context, context = context,
timestamp = envelope.timestamp!!, timestamp = envelope.clientTimestamp!!,
content = content, content = content,
metadata = metadata, metadata = metadata,
groupId = groupId, groupId = groupId,
@@ -171,7 +171,7 @@ object DataMessageProcessor {
var messageId: MessageId? = null var messageId: MessageId? = null
SignalTrace.beginSection("DataMessageProcessor#messageInsert") SignalTrace.beginSection("DataMessageProcessor#messageInsert")
when { when {
message.isInvalid -> handleInvalidMessage(context, senderRecipient.id, groupId, envelope.timestamp!!) message.isInvalid -> handleInvalidMessage(context, senderRecipient.id, groupId, envelope.clientTimestamp!!)
message.isEndSession -> insertResult = handleEndSessionMessage(context, senderRecipient.id, envelope, metadata) message.isEndSession -> insertResult = handleEndSessionMessage(context, senderRecipient.id, envelope, metadata)
message.isExpirationUpdate -> insertResult = handleExpirationUpdate(envelope, metadata, senderRecipient, threadRecipient.id, groupId, message.expireTimerDuration, message.expireTimerVersion, 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.isStoryReaction -> insertResult = handleStoryReaction(context, envelope, metadata, message, senderRecipient.id, groupId)
@@ -197,7 +197,7 @@ object DataMessageProcessor {
SignalTrace.beginSection("DataMessageProcessor#postProcess") SignalTrace.beginSection("DataMessageProcessor#postProcess")
messageId = messageId ?: insertResult?.messageId?.let { MessageId(it) } messageId = messageId ?: insertResult?.messageId?.let { MessageId(it) }
if (messageId != null) { if (messageId != null) {
log(envelope.timestamp!!, "Inserted as messageId $messageId") log(envelope.clientTimestamp!!, "Inserted as messageId $messageId")
} }
if (groupId != null) { if (groupId != null) {
@@ -206,12 +206,12 @@ object DataMessageProcessor {
else -> SignalDatabase.groups.isUnknownGroup(groupId) else -> SignalDatabase.groups.isUnknownGroup(groupId)
} }
if (unknownGroup) { if (unknownGroup) {
handleUnknownGroupMessage(envelope.timestamp!!, message.groupV2!!) handleUnknownGroupMessage(envelope.clientTimestamp!!, message.groupV2!!)
} }
} }
if (message.profileKey.isNotEmpty()) { if (message.profileKey.isNotEmpty()) {
handleProfileKey(envelope.timestamp!!, message.profileKey!!.toByteArray(), senderRecipient) handleProfileKey(envelope.clientTimestamp!!, message.profileKey!!.toByteArray(), senderRecipient)
} }
if (groupId == null && senderRecipient.hiddenState == HiddenState.HIDDEN) { if (groupId == null && senderRecipient.hiddenState == HiddenState.HIDDEN) {
@@ -248,11 +248,11 @@ object DataMessageProcessor {
if (insertResult != null && insertResult.threadWasNewlyCreated && !threadRecipient.isGroup && !threadRecipient.isSelf && !senderRecipient.isSystemContact) { if (insertResult != null && insertResult.threadWasNewlyCreated && !threadRecipient.isGroup && !threadRecipient.isSelf && !senderRecipient.isSystemContact) {
val timeSinceLastSync = System.currentTimeMillis() - SignalStore.misc.lastCdsForegroundSyncTime val timeSinceLastSync = System.currentTimeMillis() - SignalStore.misc.lastCdsForegroundSyncTime
if (timeSinceLastSync > RemoteConfig.cdsForegroundSyncInterval || timeSinceLastSync < 0) { if (timeSinceLastSync > RemoteConfig.cdsForegroundSyncInterval || timeSinceLastSync < 0) {
log(envelope.timestamp!!, "New 1:1 chat. Scheduling a CDS sync to see if they match someone in our contacts.") log(envelope.clientTimestamp!!, "New 1:1 chat. Scheduling a CDS sync to see if they match someone in our contacts.")
AppDependencies.jobManager.add(DirectoryRefreshJob(false)) AppDependencies.jobManager.add(DirectoryRefreshJob(false))
SignalStore.misc.lastCdsForegroundSyncTime = System.currentTimeMillis() SignalStore.misc.lastCdsForegroundSyncTime = System.currentTimeMillis()
} else { } else {
warn(envelope.timestamp!!, "New 1:1 chat, but performed a CDS sync $timeSinceLastSync ms ago, which is less than our threshold. Skipping CDS sync.") warn(envelope.clientTimestamp!!, "New 1:1 chat, but performed a CDS sync $timeSinceLastSync ms ago, which is less than our threshold. Skipping CDS sync.")
} }
} }
@@ -316,11 +316,11 @@ object DataMessageProcessor {
envelope: Envelope, envelope: Envelope,
metadata: EnvelopeMetadata metadata: EnvelopeMetadata
): InsertResult? { ): InsertResult? {
log(envelope.timestamp!!, "End session message.") log(envelope.clientTimestamp!!, "End session message.")
val incomingMessage = IncomingMessage( val incomingMessage = IncomingMessage(
from = senderRecipientId, from = senderRecipientId,
sentTimeMillis = envelope.timestamp!!, sentTimeMillis = envelope.clientTimestamp!!,
serverTimeMillis = envelope.serverTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!,
receivedTimeMillis = System.currentTimeMillis(), receivedTimeMillis = System.currentTimeMillis(),
isUnidentified = metadata.sealedSender, isUnidentified = metadata.sealedSender,
@@ -356,20 +356,20 @@ object DataMessageProcessor {
receivedTime: Long, receivedTime: Long,
sideEffect: Boolean sideEffect: Boolean
): InsertResult? { ): InsertResult? {
log(envelope.timestamp!!, "Expiration update. Side effect: $sideEffect") log(envelope.clientTimestamp!!, "Expiration update. Side effect: $sideEffect")
if (groupId != null) { if (groupId != null) {
warn(envelope.timestamp!!, "Expiration update received for GV2. Ignoring.") warn(envelope.clientTimestamp!!, "Expiration update received for GV2. Ignoring.")
return null return null
} }
if (SignalDatabase.recipients.getExpiresInSeconds(threadRecipientId) == expiresIn.inWholeSeconds) { if (SignalDatabase.recipients.getExpiresInSeconds(threadRecipientId) == expiresIn.inWholeSeconds) {
log(envelope.timestamp!!, "No change in message expiry for group. Ignoring.") log(envelope.clientTimestamp!!, "No change in message expiry for group. Ignoring.")
return null return null
} }
if (expireTimerVersion != null && expireTimerVersion < senderRecipient.expireTimerVersion) { if (expireTimerVersion != null && expireTimerVersion < senderRecipient.expireTimerVersion) {
log(envelope.timestamp!!, "Old expireTimerVersion. Received: $expireTimerVersion, Current: ${senderRecipient.expireTimerVersion}. Ignoring.") log(envelope.clientTimestamp!!, "Old expireTimerVersion. Received: $expireTimerVersion, Current: ${senderRecipient.expireTimerVersion}. Ignoring.")
return null return null
} }
@@ -377,7 +377,7 @@ object DataMessageProcessor {
val mediaMessage = IncomingMessage( val mediaMessage = IncomingMessage(
type = MessageType.EXPIRATION_UPDATE, type = MessageType.EXPIRATION_UPDATE,
from = senderRecipient.id, from = senderRecipient.id,
sentTimeMillis = envelope.timestamp!! - if (sideEffect) 1 else 0, sentTimeMillis = envelope.clientTimestamp!! - if (sideEffect) 1 else 0,
serverTimeMillis = envelope.serverTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!,
receivedTimeMillis = receivedTime, receivedTimeMillis = receivedTime,
expiresIn = expiresIn.inWholeMilliseconds, expiresIn = expiresIn.inWholeMilliseconds,
@@ -419,7 +419,7 @@ object DataMessageProcessor {
receivedTime: Long receivedTime: Long
) { ) {
if (threadRecipient.expiresInSeconds.toLong() != expiresIn.inWholeSeconds || ((expireTimerVersion ?: -1) > threadRecipient.expireTimerVersion)) { 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.") warn(envelope.clientTimestamp!!, "Message expire time didn't match thread expire time. Handling timer update.")
handleExpirationUpdate(envelope, metadata, senderRecipient, threadRecipient.id, groupId, expiresIn, expireTimerVersion, receivedTime, true) handleExpirationUpdate(envelope, metadata, senderRecipient, threadRecipient.id, groupId, expiresIn, expireTimerVersion, receivedTime, true)
} }
} }
@@ -433,13 +433,13 @@ object DataMessageProcessor {
senderRecipientId: RecipientId, senderRecipientId: RecipientId,
groupId: GroupId.V2? groupId: GroupId.V2?
): InsertResult? { ): InsertResult? {
log(envelope.timestamp!!, "Story reaction.") log(envelope.clientTimestamp!!, "Story reaction.")
val storyContext = message.storyContext!! val storyContext = message.storyContext!!
val emoji = message.reaction!!.emoji val emoji = message.reaction!!.emoji
if (!EmojiUtil.isEmoji(emoji)) { if (!EmojiUtil.isEmoji(emoji)) {
warn(envelope.timestamp!!, "Story reaction text is not a valid emoji! Ignoring the message.") warn(envelope.clientTimestamp!!, "Story reaction text is not a valid emoji! Ignoring the message.")
return null return null
} }
@@ -472,18 +472,18 @@ object DataMessageProcessor {
quoteModel = QuoteModel(sentTimestamp, authorRecipientId, displayText, false, story.slideDeck.asAttachments().firstOrNull(), emptyList(), QuoteModel.Type.NORMAL, bodyRanges) quoteModel = QuoteModel(sentTimestamp, authorRecipientId, displayText, false, story.slideDeck.asAttachments().firstOrNull(), emptyList(), QuoteModel.Type.NORMAL, bodyRanges)
expiresIn = message.expireTimerDuration expiresIn = message.expireTimerDuration
} else { } else {
warn(envelope.timestamp!!, "Story has reactions disabled. Dropping reaction.") warn(envelope.clientTimestamp!!, "Story has reactions disabled. Dropping reaction.")
return null return null
} }
} catch (e: NoSuchMessageException) { } catch (e: NoSuchMessageException) {
warn(envelope.timestamp!!, "Couldn't find story for reaction.", e) warn(envelope.clientTimestamp!!, "Couldn't find story for reaction.", e)
return null return null
} }
val mediaMessage = IncomingMessage( val mediaMessage = IncomingMessage(
type = MessageType.STORY_REACTION, type = MessageType.STORY_REACTION,
from = senderRecipientId, from = senderRecipientId,
sentTimeMillis = envelope.timestamp!!, sentTimeMillis = envelope.clientTimestamp!!,
serverTimeMillis = envelope.serverTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!,
receivedTimeMillis = System.currentTimeMillis(), receivedTimeMillis = System.currentTimeMillis(),
parentStoryId = parentStoryId, parentStoryId = parentStoryId,
@@ -513,7 +513,7 @@ object DataMessageProcessor {
null null
} }
} else { } else {
warn(envelope.timestamp!!, "Failed to insert story reaction") warn(envelope.clientTimestamp!!, "Failed to insert story reaction")
null null
} }
} catch (e: MmsException) { } catch (e: MmsException) {
@@ -533,7 +533,7 @@ object DataMessageProcessor {
): MessageId? { ): MessageId? {
val reaction: DataMessage.Reaction = message.reaction!! val reaction: DataMessage.Reaction = message.reaction!!
log(envelope.timestamp!!, "Handle reaction for message " + reaction.targetSentTimestamp!!) log(envelope.clientTimestamp!!, "Handle reaction for message " + reaction.targetSentTimestamp!!)
val emoji: String? = reaction.emoji val emoji: String? = reaction.emoji
val isRemove: Boolean = reaction.remove ?: false val isRemove: Boolean = reaction.remove ?: false
@@ -541,19 +541,19 @@ object DataMessageProcessor {
val targetSentTimestamp: Long = reaction.targetSentTimestamp!! val targetSentTimestamp: Long = reaction.targetSentTimestamp!!
if (targetAuthorServiceId.isUnknown) { if (targetAuthorServiceId.isUnknown) {
warn(envelope.timestamp!!, "Reaction was to an unknown UUID! Ignoring the message.") warn(envelope.clientTimestamp!!, "Reaction was to an unknown UUID! Ignoring the message.")
return null return null
} }
if (!EmojiUtil.isEmoji(emoji)) { if (!EmojiUtil.isEmoji(emoji)) {
warn(envelope.timestamp!!, "Reaction text is not a valid emoji! Ignoring the message.") warn(envelope.clientTimestamp!!, "Reaction text is not a valid emoji! Ignoring the message.")
return null return null
} }
val targetAuthor = Recipient.externalPush(targetAuthorServiceId) val targetAuthor = Recipient.externalPush(targetAuthorServiceId)
val targetMessage = SignalDatabase.messages.getMessageFor(targetSentTimestamp, targetAuthor.id) val targetMessage = SignalDatabase.messages.getMessageFor(targetSentTimestamp, targetAuthor.id)
if (targetMessage == null) { if (targetMessage == null) {
warn(envelope.timestamp!!, "[handleReaction] Could not find matching message! Putting it in the early message cache. timestamp: " + targetSentTimestamp + " author: " + targetAuthor.id) warn(envelope.clientTimestamp!!, "[handleReaction] Could not find matching message! Putting it in the early message cache. timestamp: " + targetSentTimestamp + " author: " + targetAuthor.id)
if (earlyMessageCacheEntry != null) { if (earlyMessageCacheEntry != null) {
AppDependencies.earlyMessageCache.store(targetAuthor.id, targetSentTimestamp, earlyMessageCacheEntry) AppDependencies.earlyMessageCache.store(targetAuthor.id, targetSentTimestamp, earlyMessageCacheEntry)
PushProcessEarlyMessagesJob.enqueue() PushProcessEarlyMessagesJob.enqueue()
@@ -562,25 +562,25 @@ object DataMessageProcessor {
} }
if (targetMessage.isRemoteDelete) { if (targetMessage.isRemoteDelete) {
warn(envelope.timestamp!!, "[handleReaction] Found a matching message, but it's flagged as remotely deleted. timestamp: " + targetSentTimestamp + " author: " + targetAuthor.id) warn(envelope.clientTimestamp!!, "[handleReaction] Found a matching message, but it's flagged as remotely deleted. timestamp: " + targetSentTimestamp + " author: " + targetAuthor.id)
return null return null
} }
val targetThread = SignalDatabase.threads.getThreadRecord(targetMessage.threadId) val targetThread = SignalDatabase.threads.getThreadRecord(targetMessage.threadId)
if (targetThread == null) { if (targetThread == null) {
warn(envelope.timestamp!!, "[handleReaction] Could not find a thread for the message! timestamp: " + targetSentTimestamp + " author: " + targetAuthor.id) warn(envelope.clientTimestamp!!, "[handleReaction] Could not find a thread for the message! timestamp: " + targetSentTimestamp + " author: " + targetAuthor.id)
return null return null
} }
val targetThreadRecipientId = targetThread.recipient.id val targetThreadRecipientId = targetThread.recipient.id
val groupRecord = SignalDatabase.groups.getGroup(targetThreadRecipientId).orNull() val groupRecord = SignalDatabase.groups.getGroup(targetThreadRecipientId).orNull()
if (groupRecord != null && !groupRecord.members.contains(senderRecipientId)) { if (groupRecord != null && !groupRecord.members.contains(senderRecipientId)) {
warn(envelope.timestamp!!, "[handleReaction] Reaction author is not in the group! timestamp: " + targetSentTimestamp + " author: " + targetAuthor.id) warn(envelope.clientTimestamp!!, "[handleReaction] Reaction author is not in the group! timestamp: " + targetSentTimestamp + " author: " + targetAuthor.id)
return null return null
} }
if (groupRecord == null && senderRecipientId != targetThreadRecipientId && Recipient.self().id != senderRecipientId) { if (groupRecord == null && senderRecipientId != targetThreadRecipientId && Recipient.self().id != senderRecipientId) {
warn(envelope.timestamp!!, "[handleReaction] Reaction author is not a part of the 1:1 thread! timestamp: " + targetSentTimestamp + " author: " + targetAuthor.id) warn(envelope.clientTimestamp!!, "[handleReaction] Reaction author is not a part of the 1:1 thread! timestamp: " + targetSentTimestamp + " author: " + targetAuthor.id)
return null return null
} }
@@ -601,7 +601,7 @@ object DataMessageProcessor {
fun handleRemoteDelete(context: Context, envelope: Envelope, message: DataMessage, senderRecipientId: RecipientId, earlyMessageCacheEntry: EarlyMessageCacheEntry?): MessageId? { fun handleRemoteDelete(context: Context, envelope: Envelope, message: DataMessage, senderRecipientId: RecipientId, earlyMessageCacheEntry: EarlyMessageCacheEntry?): MessageId? {
val delete = message.delete!! val delete = message.delete!!
log(envelope.timestamp!!, "Remote delete for message ${delete.targetSentTimestamp}") log(envelope.clientTimestamp!!, "Remote delete for message ${delete.targetSentTimestamp}")
val targetSentTimestamp: Long = delete.targetSentTimestamp!! val targetSentTimestamp: Long = delete.targetSentTimestamp!!
val targetMessage: MessageRecord? = SignalDatabase.messages.getMessageFor(targetSentTimestamp, senderRecipientId) val targetMessage: MessageRecord? = SignalDatabase.messages.getMessageFor(targetSentTimestamp, senderRecipientId)
@@ -616,7 +616,7 @@ object DataMessageProcessor {
MessageId(targetMessage.id) MessageId(targetMessage.id)
} else if (targetMessage == null) { } else if (targetMessage == null) {
warn(envelope.timestamp!!, "[handleRemoteDelete] Could not find matching message! timestamp: $targetSentTimestamp author: $senderRecipientId") warn(envelope.clientTimestamp!!, "[handleRemoteDelete] Could not find matching message! timestamp: $targetSentTimestamp author: $senderRecipientId")
if (earlyMessageCacheEntry != null) { if (earlyMessageCacheEntry != null) {
AppDependencies.earlyMessageCache.store(senderRecipientId, targetSentTimestamp, earlyMessageCacheEntry) AppDependencies.earlyMessageCache.store(senderRecipientId, targetSentTimestamp, earlyMessageCacheEntry)
PushProcessEarlyMessagesJob.enqueue() PushProcessEarlyMessagesJob.enqueue()
@@ -624,7 +624,7 @@ object DataMessageProcessor {
null null
} else { } else {
warn(envelope.timestamp!!, "[handleRemoteDelete] Invalid remote delete! deleteTime: ${envelope.serverTimestamp!!}, targetTime: ${targetMessage.serverTimestamp}, deleteAuthor: $senderRecipientId, targetAuthor: ${targetMessage.fromRecipient.id}") warn(envelope.clientTimestamp!!, "[handleRemoteDelete] Invalid remote delete! deleteTime: ${envelope.serverTimestamp!!}, targetTime: ${targetMessage.serverTimestamp}, deleteAuthor: $senderRecipientId, targetAuthor: ${targetMessage.fromRecipient.id}")
null null
} }
} }
@@ -644,13 +644,13 @@ object DataMessageProcessor {
isActivatePaymentsRequest: Boolean, isActivatePaymentsRequest: Boolean,
isPaymentsActivated: Boolean isPaymentsActivated: Boolean
): InsertResult? { ): InsertResult? {
log(envelope.timestamp!!, "Payment activation request: $isActivatePaymentsRequest activated: $isPaymentsActivated") log(envelope.clientTimestamp!!, "Payment activation request: $isActivatePaymentsRequest activated: $isPaymentsActivated")
Preconditions.checkArgument(isActivatePaymentsRequest || isPaymentsActivated) Preconditions.checkArgument(isActivatePaymentsRequest || isPaymentsActivated)
try { try {
val mediaMessage = IncomingMessage( val mediaMessage = IncomingMessage(
from = senderRecipientId, from = senderRecipientId,
sentTimeMillis = envelope.timestamp!!, sentTimeMillis = envelope.clientTimestamp!!,
serverTimeMillis = envelope.serverTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!,
receivedTimeMillis = receivedTime, receivedTimeMillis = receivedTime,
expiresIn = message.expireTimerDuration.inWholeMilliseconds, expiresIn = message.expireTimerDuration.inWholeMilliseconds,
@@ -675,10 +675,10 @@ object DataMessageProcessor {
senderRecipientId: RecipientId, senderRecipientId: RecipientId,
receivedTime: Long receivedTime: Long
): InsertResult? { ): InsertResult? {
log(envelope.timestamp!!, "Payment message.") log(envelope.clientTimestamp!!, "Payment message.")
if (message.payment?.notification?.mobileCoin?.receipt == null) { if (message.payment?.notification?.mobileCoin?.receipt == null) {
warn(envelope.timestamp!!, "Ignoring payment message without notification") warn(envelope.clientTimestamp!!, "Ignoring payment message without notification")
return null return null
} }
@@ -701,7 +701,7 @@ object DataMessageProcessor {
val mediaMessage = IncomingMessage( val mediaMessage = IncomingMessage(
from = senderRecipientId, from = senderRecipientId,
body = uuid.toString(), body = uuid.toString(),
sentTimeMillis = envelope.timestamp!!, sentTimeMillis = envelope.clientTimestamp!!,
serverTimeMillis = envelope.serverTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!,
receivedTimeMillis = receivedTime, receivedTimeMillis = receivedTime,
expiresIn = message.expireTimerDuration.inWholeMilliseconds, expiresIn = message.expireTimerDuration.inWholeMilliseconds,
@@ -716,9 +716,9 @@ object DataMessageProcessor {
return insertResult return insertResult
} }
} catch (e: PublicKeyConflictException) { } catch (e: PublicKeyConflictException) {
warn(envelope.timestamp!!, "Ignoring payment with public key already in database") warn(envelope.clientTimestamp!!, "Ignoring payment with public key already in database")
} catch (e: SerializationException) { } catch (e: SerializationException) {
warn(envelope.timestamp!!, "Ignoring payment with bad data.", e) warn(envelope.clientTimestamp!!, "Ignoring payment with bad data.", e)
} catch (e: MmsException) { } catch (e: MmsException) {
throw StorageFailedException(e, metadata.sourceServiceId.toString(), metadata.sourceDeviceId) throw StorageFailedException(e, metadata.sourceServiceId.toString(), metadata.sourceDeviceId)
} finally { } finally {
@@ -743,14 +743,14 @@ object DataMessageProcessor {
groupId: GroupId.V2?, groupId: GroupId.V2?,
receivedTime: Long receivedTime: Long
): InsertResult? { ): InsertResult? {
log(envelope.timestamp!!, "Story reply.") log(envelope.clientTimestamp!!, "Story reply.")
val storyContext: DataMessage.StoryContext = message.storyContext!! val storyContext: DataMessage.StoryContext = message.storyContext!!
val authorServiceId: ServiceId = ACI.parseOrThrow(storyContext.authorAci, storyContext.authorAciBinary) val authorServiceId: ServiceId = ACI.parseOrThrow(storyContext.authorAci, storyContext.authorAciBinary)
val sentTimestamp: Long = if (storyContext.sentTimestamp != null) { val sentTimestamp: Long = if (storyContext.sentTimestamp != null) {
storyContext.sentTimestamp!! storyContext.sentTimestamp!!
} else { } else {
warn(envelope.timestamp!!, "Invalid story reply, missing sentTimestamp") warn(envelope.clientTimestamp!!, "Invalid story reply, missing sentTimestamp")
return null return null
} }
@@ -798,11 +798,11 @@ object DataMessageProcessor {
quoteModel = QuoteModel(sentTimestamp, storyAuthorRecipientId, displayText, false, story.slideDeck.asAttachments().firstOrNull(), emptyList(), QuoteModel.Type.NORMAL, bodyRanges) quoteModel = QuoteModel(sentTimestamp, storyAuthorRecipientId, displayText, false, story.slideDeck.asAttachments().firstOrNull(), emptyList(), QuoteModel.Type.NORMAL, bodyRanges)
expiresInMillis = message.expireTimerDuration expiresInMillis = message.expireTimerDuration
} else { } else {
warn(envelope.timestamp!!, "Story has replies disabled. Dropping reply.") warn(envelope.clientTimestamp!!, "Story has replies disabled. Dropping reply.")
return null return null
} }
} catch (e: NoSuchMessageException) { } catch (e: NoSuchMessageException) {
warn(envelope.timestamp!!, "Couldn't find story for reply.", e) warn(envelope.clientTimestamp!!, "Couldn't find story for reply.", e)
return null return null
} }
@@ -811,7 +811,7 @@ object DataMessageProcessor {
val mediaMessage = IncomingMessage( val mediaMessage = IncomingMessage(
type = MessageType.NORMAL, type = MessageType.NORMAL,
from = senderRecipient.id, from = senderRecipient.id,
sentTimeMillis = envelope.timestamp!!, sentTimeMillis = envelope.clientTimestamp!!,
serverTimeMillis = envelope.serverTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!,
receivedTimeMillis = System.currentTimeMillis(), receivedTimeMillis = System.currentTimeMillis(),
parentStoryId = parentStoryId, parentStoryId = parentStoryId,
@@ -843,7 +843,7 @@ object DataMessageProcessor {
null null
} }
} else { } else {
warn(envelope.timestamp!!, "Failed to insert story reply.") warn(envelope.clientTimestamp!!, "Failed to insert story reply.")
null null
} }
} catch (e: MmsException) { } catch (e: MmsException) {
@@ -880,7 +880,7 @@ object DataMessageProcessor {
val mediaMessage = IncomingMessage( val mediaMessage = IncomingMessage(
type = MessageType.NORMAL, type = MessageType.NORMAL,
from = senderRecipient.id, from = senderRecipient.id,
sentTimeMillis = envelope.timestamp!!, sentTimeMillis = envelope.clientTimestamp!!,
serverTimeMillis = envelope.serverTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!,
receivedTimeMillis = receivedTime, receivedTimeMillis = receivedTime,
expiresIn = message.expireTimerDuration.inWholeMilliseconds, expiresIn = message.expireTimerDuration.inWholeMilliseconds,
@@ -917,7 +917,7 @@ object DataMessageProcessor {
localMetrics: SignalLocalMetrics.MessageReceive?, localMetrics: SignalLocalMetrics.MessageReceive?,
batchCache: BatchCache batchCache: BatchCache
): InsertResult? { ): InsertResult? {
log(envelope.timestamp!!, "Media message.") log(envelope.clientTimestamp!!, "Media message.")
notifyTypingStoppedFromIncomingMessage(context, senderRecipient, threadRecipient.id, metadata.sourceDeviceId) notifyTypingStoppedFromIncomingMessage(context, senderRecipient, threadRecipient.id, metadata.sourceDeviceId)
@@ -925,11 +925,11 @@ object DataMessageProcessor {
SignalDatabase.messages.beginTransaction() SignalDatabase.messages.beginTransaction()
try { try {
val quoteModel: QuoteModel? = getValidatedQuote(context, envelope.timestamp!!, message, senderRecipient, threadRecipient) val quoteModel: QuoteModel? = getValidatedQuote(context, envelope.clientTimestamp!!, message, senderRecipient, threadRecipient)
val contacts: List<Contact> = getContacts(message) val contacts: List<Contact> = getContacts(message)
val linkPreviews: List<LinkPreview> = getLinkPreviews(message.preview, message.body ?: "", false) val linkPreviews: List<LinkPreview> = getLinkPreviews(message.preview, message.body ?: "", false)
val mentions: List<Mention> = getMentions(message.bodyRanges.take(BODY_RANGE_PROCESSING_LIMIT)) val mentions: List<Mention> = getMentions(message.bodyRanges.take(BODY_RANGE_PROCESSING_LIMIT))
val sticker: Attachment? = getStickerAttachment(envelope.timestamp!!, message) val sticker: Attachment? = getStickerAttachment(envelope.clientTimestamp!!, message)
val attachments: List<Attachment> = message.attachments.toPointersWithinLimit() val attachments: List<Attachment> = message.attachments.toPointersWithinLimit()
val messageRanges: BodyRangeList? = if (message.bodyRanges.isNotEmpty()) message.bodyRanges.asSequence().take(BODY_RANGE_PROCESSING_LIMIT).filter { Util.allAreNull(it.mentionAci, it.mentionAciBinary) }.toList().toBodyRangeList() else null val messageRanges: BodyRangeList? = if (message.bodyRanges.isNotEmpty()) message.bodyRanges.asSequence().take(BODY_RANGE_PROCESSING_LIMIT).filter { Util.allAreNull(it.mentionAci, it.mentionAciBinary) }.toList().toBodyRangeList() else null
@@ -938,7 +938,7 @@ object DataMessageProcessor {
val mediaMessage = IncomingMessage( val mediaMessage = IncomingMessage(
type = MessageType.NORMAL, type = MessageType.NORMAL,
from = senderRecipient.id, from = senderRecipient.id,
sentTimeMillis = envelope.timestamp!!, sentTimeMillis = envelope.clientTimestamp!!,
serverTimeMillis = envelope.serverTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!,
receivedTimeMillis = receivedTime, receivedTimeMillis = receivedTime,
expiresIn = message.expireTimerDuration.inWholeMilliseconds, expiresIn = message.expireTimerDuration.inWholeMilliseconds,
@@ -1018,7 +1018,7 @@ object DataMessageProcessor {
localMetrics: SignalLocalMetrics.MessageReceive?, localMetrics: SignalLocalMetrics.MessageReceive?,
batchCache: BatchCache batchCache: BatchCache
): InsertResult? { ): InsertResult? {
log(envelope.timestamp!!, "Text message.") log(envelope.clientTimestamp!!, "Text message.")
val body = message.body ?: "" val body = message.body ?: ""
@@ -1029,7 +1029,7 @@ object DataMessageProcessor {
val textMessage = IncomingMessage( val textMessage = IncomingMessage(
type = MessageType.NORMAL, type = MessageType.NORMAL,
from = senderRecipient.id, from = senderRecipient.id,
sentTimeMillis = envelope.timestamp!!, sentTimeMillis = envelope.clientTimestamp!!,
serverTimeMillis = envelope.serverTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!,
receivedTimeMillis = receivedTime, receivedTimeMillis = receivedTime,
body = body, body = body,
@@ -1058,15 +1058,15 @@ object DataMessageProcessor {
senderRecipientId: RecipientId, senderRecipientId: RecipientId,
groupId: GroupId.V2? groupId: GroupId.V2?
) { ) {
log(envelope.timestamp!!, "Group call update message.") log(envelope.clientTimestamp!!, "Group call update message.")
if (groupId == null) { if (groupId == null) {
warn(envelope.timestamp!!, "Invalid group for group call update message") warn(envelope.clientTimestamp!!, "Invalid group for group call update message")
return return
} }
if (!SignalDatabase.groups.groupExists(groupId)) { if (!SignalDatabase.groups.groupExists(groupId)) {
warn(envelope.timestamp!!, "Received group call update message for unknown groupId: $groupId") warn(envelope.clientTimestamp!!, "Received group call update message for unknown groupId: $groupId")
return return
} }
@@ -1091,7 +1091,7 @@ object DataMessageProcessor {
groupId: GroupId.V2?, groupId: GroupId.V2?,
receivedTime: Long receivedTime: Long
): InsertResult? { ): InsertResult? {
log(envelope.timestamp!!, "Handle poll creation") log(envelope.clientTimestamp!!, "Handle poll creation")
val poll: DataMessage.PollCreate = message.pollCreate!! val poll: DataMessage.PollCreate = message.pollCreate!!
handlePossibleExpirationUpdate(envelope, metadata, senderRecipient, threadRecipient, groupId, message.expireTimerDuration, message.expireTimerVersion, receivedTime) handlePossibleExpirationUpdate(envelope, metadata, senderRecipient, threadRecipient, groupId, message.expireTimerDuration, message.expireTimerVersion, receivedTime)
@@ -1099,28 +1099,28 @@ object DataMessageProcessor {
if (groupId != null) { if (groupId != null) {
val groupRecord = SignalDatabase.groups.getGroup(groupId).orNull() val groupRecord = SignalDatabase.groups.getGroup(groupId).orNull()
if (groupRecord != null && !groupRecord.members.contains(senderRecipient.id)) { if (groupRecord != null && !groupRecord.members.contains(senderRecipient.id)) {
warn(envelope.timestamp!!, "[handlePollCreate] Poll author is not in the group. author $senderRecipient") warn(envelope.clientTimestamp!!, "[handlePollCreate] Poll author is not in the group. author $senderRecipient")
return null return null
} }
} else if (senderRecipient.id != threadRecipient.id && senderRecipient.id != Recipient.self().id) { } else if (senderRecipient.id != threadRecipient.id && senderRecipient.id != Recipient.self().id) {
warn(envelope.timestamp!!, "[handlePollCreate] Sender is not a part of the 1:1 thread!") warn(envelope.clientTimestamp!!, "[handlePollCreate] Sender is not a part of the 1:1 thread!")
return null return null
} }
if (poll.question == null || poll.question!!.isEmpty() || poll.question!!.length > POLL_QUESTION_CHARACTER_LIMIT) { if (poll.question == null || poll.question!!.isEmpty() || poll.question!!.length > POLL_QUESTION_CHARACTER_LIMIT) {
warn(envelope.timestamp!!, "[handlePollCreate] Poll question is invalid.") warn(envelope.clientTimestamp!!, "[handlePollCreate] Poll question is invalid.")
return null return null
} }
if (poll.options.isEmpty() || poll.options.size > POLL_OPTIONS_LIMIT || poll.options.any { it.isEmpty() || it.length > POLL_CHARACTER_LIMIT }) { if (poll.options.isEmpty() || poll.options.size > POLL_OPTIONS_LIMIT || poll.options.any { it.isEmpty() || it.length > POLL_CHARACTER_LIMIT }) {
warn(envelope.timestamp!!, "[handlePollCreate] Poll option is invalid.") warn(envelope.clientTimestamp!!, "[handlePollCreate] Poll option is invalid.")
return null return null
} }
val pollMessage = IncomingMessage( val pollMessage = IncomingMessage(
type = MessageType.NORMAL, type = MessageType.NORMAL,
from = senderRecipient.id, from = senderRecipient.id,
sentTimeMillis = envelope.timestamp!!, sentTimeMillis = envelope.clientTimestamp!!,
serverTimeMillis = envelope.serverTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!,
receivedTimeMillis = receivedTime, receivedTimeMillis = receivedTime,
groupId = groupId, groupId = groupId,
@@ -1159,7 +1159,7 @@ object DataMessageProcessor {
val pollTerminate: DataMessage.PollTerminate = message.pollTerminate!! val pollTerminate: DataMessage.PollTerminate = message.pollTerminate!!
val targetSentTimestamp = pollTerminate.targetSentTimestamp!! val targetSentTimestamp = pollTerminate.targetSentTimestamp!!
log(envelope.timestamp!!, "Handle poll termination for poll $targetSentTimestamp") log(envelope.clientTimestamp!!, "Handle poll termination for poll $targetSentTimestamp")
handlePossibleExpirationUpdate(envelope, metadata, senderRecipient, threadRecipient, groupId, message.expireTimerDuration, message.expireTimerVersion, receivedTime) handlePossibleExpirationUpdate(envelope, metadata, senderRecipient, threadRecipient, groupId, message.expireTimerDuration, message.expireTimerVersion, receivedTime)
@@ -1170,14 +1170,14 @@ object DataMessageProcessor {
val poll = SignalDatabase.polls.getPoll(messageId.id) val poll = SignalDatabase.polls.getPoll(messageId.id)
if (poll == null) { if (poll == null) {
warn(envelope.timestamp!!, "[handlePollTerminate] Poll was not found. timestamp: $targetSentTimestamp author: ${senderRecipient.id}") warn(envelope.clientTimestamp!!, "[handlePollTerminate] Poll was not found. timestamp: $targetSentTimestamp author: ${senderRecipient.id}")
return null return null
} }
val pollMessage = IncomingMessage( val pollMessage = IncomingMessage(
type = MessageType.POLL_TERMINATE, type = MessageType.POLL_TERMINATE,
from = senderRecipient.id, from = senderRecipient.id,
sentTimeMillis = envelope.timestamp!!, sentTimeMillis = envelope.clientTimestamp!!,
serverTimeMillis = envelope.serverTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!,
receivedTimeMillis = receivedTime, receivedTimeMillis = receivedTime,
groupId = groupId, groupId = groupId,
@@ -1207,11 +1207,11 @@ object DataMessageProcessor {
val pollVote: DataMessage.PollVote = message.pollVote!! val pollVote: DataMessage.PollVote = message.pollVote!!
val targetSentTimestamp = pollVote.targetSentTimestamp!! val targetSentTimestamp = pollVote.targetSentTimestamp!!
log(envelope.timestamp!!, "Handle poll vote for poll $targetSentTimestamp") log(envelope.clientTimestamp!!, "Handle poll vote for poll $targetSentTimestamp")
val targetAuthorServiceId: ServiceId = ServiceId.parseOrThrow(pollVote.targetAuthorAciBinary!!) val targetAuthorServiceId: ServiceId = ServiceId.parseOrThrow(pollVote.targetAuthorAciBinary!!)
if (targetAuthorServiceId.isUnknown) { if (targetAuthorServiceId.isUnknown) {
warn(envelope.timestamp!!, "[handlePollVote] Vote was to an unknown UUID! Ignoring the message.") warn(envelope.clientTimestamp!!, "[handlePollVote] Vote was to an unknown UUID! Ignoring the message.")
return null return null
} }
@@ -1223,30 +1223,30 @@ object DataMessageProcessor {
val targetMessage = SignalDatabase.messages.getMessageRecord(messageId.id) val targetMessage = SignalDatabase.messages.getMessageRecord(messageId.id)
val pollId = SignalDatabase.polls.getPollId(messageId.id) val pollId = SignalDatabase.polls.getPollId(messageId.id)
if (pollId == null) { if (pollId == null) {
warn(envelope.timestamp!!, "[handlePollVote] Poll was not found. timestamp: $targetSentTimestamp author: ${senderRecipient.id}") warn(envelope.clientTimestamp!!, "[handlePollVote] Poll was not found. timestamp: $targetSentTimestamp author: ${senderRecipient.id}")
return null return null
} }
val existingVoteCount = SignalDatabase.polls.getCurrentPollVoteCount(pollId, senderRecipient.id.toLong()) val existingVoteCount = SignalDatabase.polls.getCurrentPollVoteCount(pollId, senderRecipient.id.toLong())
val currentVoteCount = pollVote.voteCount?.toLong() ?: 0 val currentVoteCount = pollVote.voteCount?.toLong() ?: 0
if (currentVoteCount <= existingVoteCount) { if (currentVoteCount <= existingVoteCount) {
warn(envelope.timestamp!!, "[handlePollVote] Incoming vote count was not higher. timestamp: $targetSentTimestamp author: ${senderRecipient.id}") warn(envelope.clientTimestamp!!, "[handlePollVote] Incoming vote count was not higher. timestamp: $targetSentTimestamp author: ${senderRecipient.id}")
return null return null
} }
val allOptionIds = SignalDatabase.polls.getPollOptionIds(pollId) val allOptionIds = SignalDatabase.polls.getPollOptionIds(pollId)
if (pollVote.optionIndexes.any { it < 0 || it >= allOptionIds.size }) { if (pollVote.optionIndexes.any { it < 0 || it >= allOptionIds.size }) {
warn(envelope.timestamp!!, "[handlePollVote] Invalid option indexes. timestamp: $targetSentTimestamp author: ${senderRecipient.id}") warn(envelope.clientTimestamp!!, "[handlePollVote] Invalid option indexes. timestamp: $targetSentTimestamp author: ${senderRecipient.id}")
return null return null
} }
if (!SignalDatabase.polls.canAllowMultipleVotes(pollId) && pollVote.optionIndexes.size > 1) { if (!SignalDatabase.polls.canAllowMultipleVotes(pollId) && pollVote.optionIndexes.size > 1) {
warn(envelope.timestamp!!, "[handlePollVote] Can not vote multiple times. timestamp: $targetSentTimestamp author: ${senderRecipient.id}") warn(envelope.clientTimestamp!!, "[handlePollVote] Can not vote multiple times. timestamp: $targetSentTimestamp author: ${senderRecipient.id}")
return null return null
} }
if (SignalDatabase.polls.hasEnded(pollId)) { if (SignalDatabase.polls.hasEnded(pollId)) {
warn(envelope.timestamp!!, "[handlePollVote] Poll has already ended. timestamp: $targetSentTimestamp author: ${senderRecipient.id}") warn(envelope.clientTimestamp!!, "[handlePollVote] Poll has already ended. timestamp: $targetSentTimestamp author: ${senderRecipient.id}")
return null return null
} }
@@ -1274,13 +1274,13 @@ object DataMessageProcessor {
earlyMessageCacheEntry: EarlyMessageCacheEntry? = null earlyMessageCacheEntry: EarlyMessageCacheEntry? = null
): InsertResult? { ): InsertResult? {
val pinMessage = message.pinMessage!! val pinMessage = message.pinMessage!!
log(envelope.timestamp!!, "[handlePinMessage] Pin message for " + pinMessage.targetSentTimestamp) log(envelope.clientTimestamp!!, "[handlePinMessage] Pin message for " + pinMessage.targetSentTimestamp)
handlePossibleExpirationUpdate(envelope, metadata, senderRecipient, threadRecipient, groupId, message.expireTimerDuration, message.expireTimerVersion, receivedTime) handlePossibleExpirationUpdate(envelope, metadata, senderRecipient, threadRecipient, groupId, message.expireTimerDuration, message.expireTimerVersion, receivedTime)
val targetAuthorServiceId: ServiceId = ACI.parseOrThrow(pinMessage.targetAuthorAciBinary!!) val targetAuthorServiceId: ServiceId = ACI.parseOrThrow(pinMessage.targetAuthorAciBinary!!)
if (targetAuthorServiceId.isUnknown) { if (targetAuthorServiceId.isUnknown) {
warn(envelope.timestamp!!, "[handlePinMessage] Unknown target author! Ignoring the message.") warn(envelope.clientTimestamp!!, "[handlePinMessage] Unknown target author! Ignoring the message.")
return null return null
} }
@@ -1288,7 +1288,7 @@ object DataMessageProcessor {
val targetMessage: MmsMessageRecord? = SignalDatabase.messages.getMessageFor(pinMessage.targetSentTimestamp!!, targetAuthor.id) as? MmsMessageRecord val targetMessage: MmsMessageRecord? = SignalDatabase.messages.getMessageFor(pinMessage.targetSentTimestamp!!, targetAuthor.id) as? MmsMessageRecord
if (targetMessage == null) { if (targetMessage == null) {
warn(envelope.timestamp!!, "[handlePinMessage] Could not find matching message! Putting it in the early message cache. timestamp: ${pinMessage.targetSentTimestamp}") warn(envelope.clientTimestamp!!, "[handlePinMessage] Could not find matching message! Putting it in the early message cache. timestamp: ${pinMessage.targetSentTimestamp}")
if (earlyMessageCacheEntry != null) { if (earlyMessageCacheEntry != null) {
AppDependencies.earlyMessageCache.store(targetAuthor.id, pinMessage.targetSentTimestamp!!, earlyMessageCacheEntry) AppDependencies.earlyMessageCache.store(targetAuthor.id, pinMessage.targetSentTimestamp!!, earlyMessageCacheEntry)
PushProcessEarlyMessagesJob.enqueue() PushProcessEarlyMessagesJob.enqueue()
@@ -1297,38 +1297,38 @@ object DataMessageProcessor {
} }
if (targetMessage.isRemoteDelete) { if (targetMessage.isRemoteDelete) {
warn(envelope.timestamp!!, "[handlePinMessage] Found a matching message, but it's flagged as remotely deleted. timestamp: ${pinMessage.targetSentTimestamp}") warn(envelope.clientTimestamp!!, "[handlePinMessage] Found a matching message, but it's flagged as remotely deleted. timestamp: ${pinMessage.targetSentTimestamp}")
return null return null
} }
if (targetMessage.hasGiftBadge()) { if (targetMessage.hasGiftBadge()) {
warn(envelope.timestamp!!, "[handlePinMessage] Cannot pin a gift badge") warn(envelope.clientTimestamp!!, "[handlePinMessage] Cannot pin a gift badge")
return null return null
} }
val targetThread = SignalDatabase.threads.getThreadRecord(targetMessage.threadId) val targetThread = SignalDatabase.threads.getThreadRecord(targetMessage.threadId)
if (targetThread == null) { if (targetThread == null) {
warn(envelope.timestamp!!, "[handlePinMessage] Could not find a thread for the message! timestamp: ${pinMessage.targetSentTimestamp}") warn(envelope.clientTimestamp!!, "[handlePinMessage] Could not find a thread for the message! timestamp: ${pinMessage.targetSentTimestamp}")
return null return null
} }
if (targetThread.recipient.id != threadRecipient.id) { if (targetThread.recipient.id != threadRecipient.id) {
warn(envelope.timestamp!!, "[handlePinMessage] Target message is in a different thread than the thread recipient! timestamp: ${pinMessage.targetSentTimestamp}") warn(envelope.clientTimestamp!!, "[handlePinMessage] Target message is in a different thread than the thread recipient! timestamp: ${pinMessage.targetSentTimestamp}")
return null return null
} }
val groupRecord = SignalDatabase.groups.getGroup(threadRecipient.id).orNull() val groupRecord = SignalDatabase.groups.getGroup(threadRecipient.id).orNull()
if (groupRecord != null && !groupRecord.members.contains(senderRecipient.id)) { if (groupRecord != null && !groupRecord.members.contains(senderRecipient.id)) {
warn(envelope.timestamp!!, "[handlePinMessage] Sender is not in the group! timestamp: ${pinMessage.targetSentTimestamp}") warn(envelope.clientTimestamp!!, "[handlePinMessage] Sender is not in the group! timestamp: ${pinMessage.targetSentTimestamp}")
return null return null
} }
if (groupRecord != null && groupRecord.attributesAccessControl == GroupAccessControl.ONLY_ADMINS && !groupRecord.isAdmin(senderRecipient)) { if (groupRecord != null && groupRecord.attributesAccessControl == GroupAccessControl.ONLY_ADMINS && !groupRecord.isAdmin(senderRecipient)) {
warn(envelope.timestamp!!, "[handlePinMessage] Sender needs to be an admin! timestamp: ${pinMessage.targetSentTimestamp}") warn(envelope.clientTimestamp!!, "[handlePinMessage] Sender needs to be an admin! timestamp: ${pinMessage.targetSentTimestamp}")
return null return null
} }
if (groupRecord == null && senderRecipient.id != threadRecipient.id && Recipient.self().id != senderRecipient.id) { if (groupRecord == null && senderRecipient.id != threadRecipient.id && Recipient.self().id != senderRecipient.id) {
warn(envelope.timestamp!!, "[handlePinMessage] Sender is not a part of the 1:1 thread! timestamp: ${pinMessage.targetSentTimestamp}") warn(envelope.clientTimestamp!!, "[handlePinMessage] Sender is not a part of the 1:1 thread! timestamp: ${pinMessage.targetSentTimestamp}")
return null return null
} }
@@ -1337,7 +1337,7 @@ object DataMessageProcessor {
val pinnedMessage = IncomingMessage( val pinnedMessage = IncomingMessage(
type = MessageType.PINNED_MESSAGE, type = MessageType.PINNED_MESSAGE,
from = senderRecipient.id, from = senderRecipient.id,
sentTimeMillis = envelope.timestamp!!, sentTimeMillis = envelope.clientTimestamp!!,
serverTimeMillis = envelope.serverTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!,
receivedTimeMillis = receivedTime, receivedTimeMillis = receivedTime,
expiresIn = message.expireTimerDuration.inWholeMilliseconds, expiresIn = message.expireTimerDuration.inWholeMilliseconds,
@@ -1350,7 +1350,7 @@ object DataMessageProcessor {
val insertResult: InsertResult? = SignalDatabase.messages.insertMessageInbox(pinnedMessage).orNull() val insertResult: InsertResult? = SignalDatabase.messages.insertMessageInbox(pinnedMessage).orNull()
return if (insertResult != null) { return if (insertResult != null) {
log(envelope.timestamp!!, "Inserted a pinned message update at ${insertResult.messageId}") log(envelope.clientTimestamp!!, "Inserted a pinned message update at ${insertResult.messageId}")
if (duration != MessageTable.PIN_FOREVER) { if (duration != MessageTable.PIN_FOREVER) {
AppDependencies.pinnedMessageManager.scheduleIfNecessary() AppDependencies.pinnedMessageManager.scheduleIfNecessary()
} }
@@ -1368,11 +1368,11 @@ object DataMessageProcessor {
earlyMessageCacheEntry: EarlyMessageCacheEntry? = null earlyMessageCacheEntry: EarlyMessageCacheEntry? = null
): MessageId? { ): MessageId? {
val unpinMessage = message.unpinMessage!! val unpinMessage = message.unpinMessage!!
log(envelope.timestamp!!, "[handleUnpinMessage] Unpin message for ${unpinMessage.targetSentTimestamp}") log(envelope.clientTimestamp!!, "[handleUnpinMessage] Unpin message for ${unpinMessage.targetSentTimestamp}")
val targetAuthorServiceId: ServiceId = ACI.parseOrThrow(unpinMessage.targetAuthorAciBinary!!) val targetAuthorServiceId: ServiceId = ACI.parseOrThrow(unpinMessage.targetAuthorAciBinary!!)
if (targetAuthorServiceId.isUnknown) { if (targetAuthorServiceId.isUnknown) {
warn(envelope.timestamp!!, "[handleUnpinMessage] Unknown target author! Ignoring the message.") warn(envelope.clientTimestamp!!, "[handleUnpinMessage] Unknown target author! Ignoring the message.")
return null return null
} }
@@ -1380,7 +1380,7 @@ object DataMessageProcessor {
val targetMessage: MmsMessageRecord? = SignalDatabase.messages.getMessageFor(unpinMessage.targetSentTimestamp!!, targetAuthor.id) as? MmsMessageRecord val targetMessage: MmsMessageRecord? = SignalDatabase.messages.getMessageFor(unpinMessage.targetSentTimestamp!!, targetAuthor.id) as? MmsMessageRecord
if (targetMessage == null) { if (targetMessage == null) {
warn(envelope.timestamp!!, "[handleUnpinMessage] Could not find matching message! Putting it in the early message cache. timestamp: ${unpinMessage.targetSentTimestamp}") warn(envelope.clientTimestamp!!, "[handleUnpinMessage] Could not find matching message! Putting it in the early message cache. timestamp: ${unpinMessage.targetSentTimestamp}")
if (earlyMessageCacheEntry != null) { if (earlyMessageCacheEntry != null) {
AppDependencies.earlyMessageCache.store(targetAuthor.id, unpinMessage.targetSentTimestamp!!, earlyMessageCacheEntry) AppDependencies.earlyMessageCache.store(targetAuthor.id, unpinMessage.targetSentTimestamp!!, earlyMessageCacheEntry)
PushProcessEarlyMessagesJob.enqueue() PushProcessEarlyMessagesJob.enqueue()
@@ -1389,38 +1389,38 @@ object DataMessageProcessor {
} }
if (targetMessage.isRemoteDelete) { if (targetMessage.isRemoteDelete) {
warn(envelope.timestamp!!, "[handleUnpinMessage] Found a matching message, but it's flagged as remotely deleted. timestamp: ${unpinMessage.targetSentTimestamp}") warn(envelope.clientTimestamp!!, "[handleUnpinMessage] Found a matching message, but it's flagged as remotely deleted. timestamp: ${unpinMessage.targetSentTimestamp}")
return null return null
} }
if (targetMessage.hasGiftBadge()) { if (targetMessage.hasGiftBadge()) {
warn(envelope.timestamp!!, "[handleUnpinMessage] Cannot pin a gift badge") warn(envelope.clientTimestamp!!, "[handleUnpinMessage] Cannot pin a gift badge")
return null return null
} }
val targetThread = SignalDatabase.threads.getThreadRecord(targetMessage.threadId) val targetThread = SignalDatabase.threads.getThreadRecord(targetMessage.threadId)
if (targetThread == null) { if (targetThread == null) {
warn(envelope.timestamp!!, "[handleUnpinMessage] Could not find a thread for the message! timestamp: ${unpinMessage.targetSentTimestamp}") warn(envelope.clientTimestamp!!, "[handleUnpinMessage] Could not find a thread for the message! timestamp: ${unpinMessage.targetSentTimestamp}")
return null return null
} }
if (targetThread.recipient.id != threadRecipient.id) { if (targetThread.recipient.id != threadRecipient.id) {
warn(envelope.timestamp!!, "[handleUnpinMessage] Target message is in a different thread than the thread recipient! timestamp: ${unpinMessage.targetSentTimestamp}") warn(envelope.clientTimestamp!!, "[handleUnpinMessage] Target message is in a different thread than the thread recipient! timestamp: ${unpinMessage.targetSentTimestamp}")
return null return null
} }
val groupRecord = SignalDatabase.groups.getGroup(threadRecipient.id).orNull() val groupRecord = SignalDatabase.groups.getGroup(threadRecipient.id).orNull()
if (groupRecord != null && !groupRecord.members.contains(senderRecipient.id)) { if (groupRecord != null && !groupRecord.members.contains(senderRecipient.id)) {
warn(envelope.timestamp!!, "[handleUnpinMessage] Sender is not in the group! timestamp: ${unpinMessage.targetSentTimestamp}") warn(envelope.clientTimestamp!!, "[handleUnpinMessage] Sender is not in the group! timestamp: ${unpinMessage.targetSentTimestamp}")
return null return null
} }
if (groupRecord != null && groupRecord.attributesAccessControl == GroupAccessControl.ONLY_ADMINS && !groupRecord.isAdmin(senderRecipient)) { if (groupRecord != null && groupRecord.attributesAccessControl == GroupAccessControl.ONLY_ADMINS && !groupRecord.isAdmin(senderRecipient)) {
warn(envelope.timestamp!!, "[handleUnpinMessage] Sender needs to be an admin! timestamp: ${unpinMessage.targetSentTimestamp}") warn(envelope.clientTimestamp!!, "[handleUnpinMessage] Sender needs to be an admin! timestamp: ${unpinMessage.targetSentTimestamp}")
return null return null
} }
if (groupRecord == null && senderRecipient.id != threadRecipient.id && Recipient.self().id != senderRecipient.id) { if (groupRecord == null && senderRecipient.id != threadRecipient.id && Recipient.self().id != senderRecipient.id) {
warn(envelope.timestamp!!, "[handleUnpinMessage] Sender is not a part of the 1:1 thread! timestamp: ${unpinMessage.targetSentTimestamp}") warn(envelope.clientTimestamp!!, "[handleUnpinMessage] Sender is not a part of the 1:1 thread! timestamp: ${unpinMessage.targetSentTimestamp}")
return null return null
} }
@@ -1432,25 +1432,25 @@ object DataMessageProcessor {
fun handleAdminRemoteDelete(context: Context, envelope: Envelope, message: DataMessage, senderRecipient: Recipient, threadRecipient: Recipient, earlyMessageCacheEntry: EarlyMessageCacheEntry?): MessageId? { fun handleAdminRemoteDelete(context: Context, envelope: Envelope, message: DataMessage, senderRecipient: Recipient, threadRecipient: Recipient, earlyMessageCacheEntry: EarlyMessageCacheEntry?): MessageId? {
if (!RemoteConfig.receiveAdminDelete) { if (!RemoteConfig.receiveAdminDelete) {
log(envelope.timestamp!!, "Admin delete is not allowed due to remote config.") log(envelope.clientTimestamp!!, "Admin delete is not allowed due to remote config.")
return null return null
} }
val delete = message.adminDelete!! val delete = message.adminDelete!!
log(envelope.timestamp!!, "Admin delete for message ${delete.targetSentTimestamp}") log(envelope.clientTimestamp!!, "Admin delete for message ${delete.targetSentTimestamp}")
val targetSentTimestamp: Long = delete.targetSentTimestamp!! val targetSentTimestamp: Long = delete.targetSentTimestamp!!
val targetAuthorServiceId: ServiceId = ACI.parseOrThrow(delete.targetAuthorAciBinary!!) val targetAuthorServiceId: ServiceId = ACI.parseOrThrow(delete.targetAuthorAciBinary!!)
if (targetAuthorServiceId.isUnknown) { if (targetAuthorServiceId.isUnknown) {
warn(envelope.timestamp!!, "[handleAdminRemoteDelete] Invalid author.") warn(envelope.clientTimestamp!!, "[handleAdminRemoteDelete] Invalid author.")
return null return null
} }
val targetAuthor = Recipient.externalPush(targetAuthorServiceId) val targetAuthor = Recipient.externalPush(targetAuthorServiceId)
val targetMessage: MessageRecord? = SignalDatabase.messages.getMessageFor(targetSentTimestamp, targetAuthor.id) val targetMessage: MessageRecord? = SignalDatabase.messages.getMessageFor(targetSentTimestamp, targetAuthor.id)
if (targetMessage == null) { if (targetMessage == null) {
warn(envelope.timestamp!!, "[handleAdminRemoteDelete] Could not find matching message! timestamp: $targetSentTimestamp") warn(envelope.clientTimestamp!!, "[handleAdminRemoteDelete] Could not find matching message! timestamp: $targetSentTimestamp")
if (earlyMessageCacheEntry != null) { if (earlyMessageCacheEntry != null) {
AppDependencies.earlyMessageCache.store(targetAuthor.id, targetSentTimestamp, earlyMessageCacheEntry) AppDependencies.earlyMessageCache.store(targetAuthor.id, targetSentTimestamp, earlyMessageCacheEntry)
PushProcessEarlyMessagesJob.enqueue() PushProcessEarlyMessagesJob.enqueue()
@@ -1460,19 +1460,19 @@ object DataMessageProcessor {
val targetThread = SignalDatabase.threads.getThreadRecord(targetMessage.threadId) val targetThread = SignalDatabase.threads.getThreadRecord(targetMessage.threadId)
if (targetThread == null) { if (targetThread == null) {
warn(envelope.timestamp!!, "[handleAdminRemoteDelete] Could not find a thread for the message! timestamp: $targetSentTimestamp author: ${targetAuthor.id}") warn(envelope.clientTimestamp!!, "[handleAdminRemoteDelete] Could not find a thread for the message! timestamp: $targetSentTimestamp author: ${targetAuthor.id}")
return null return null
} }
val targetThreadRecipientId = targetThread.recipient.id val targetThreadRecipientId = targetThread.recipient.id
if (targetThreadRecipientId != threadRecipient.id) { if (targetThreadRecipientId != threadRecipient.id) {
warn(envelope.timestamp!!, "[handleAdminRemoteDelete] Target message is in a different thread than the admin delete! timestamp: $targetSentTimestamp") warn(envelope.clientTimestamp!!, "[handleAdminRemoteDelete] Target message is in a different thread than the admin delete! timestamp: $targetSentTimestamp")
return null return null
} }
val groupRecord = SignalDatabase.groups.getGroup(targetThreadRecipientId).orNull() val groupRecord = SignalDatabase.groups.getGroup(targetThreadRecipientId).orNull()
if (groupRecord == null || !groupRecord.isV2Group) { if (groupRecord == null || !groupRecord.isV2Group) {
warn(envelope.timestamp!!, "[handleAdminRemoteDelete] Invalid group.") warn(envelope.clientTimestamp!!, "[handleAdminRemoteDelete] Invalid group.")
return null return null
} }
@@ -1481,7 +1481,7 @@ object DataMessageProcessor {
AppDependencies.messageNotifier.updateNotification(context, ConversationId.fromMessageRecord(targetMessage)) AppDependencies.messageNotifier.updateNotification(context, ConversationId.fromMessageRecord(targetMessage))
MessageId(targetMessage.id) MessageId(targetMessage.id)
} else { } else {
warn(envelope.timestamp!!, "[handleAdminRemoteDelete] Invalid admin delete! deleteTime: ${envelope.serverTimestamp!!}, targetTime: ${targetMessage.serverTimestamp}, deleteAuthor: ${senderRecipient.id}, targetAuthor: ${targetMessage.fromRecipient.id}, isAdmin: ${groupRecord.isAdmin(senderRecipient)}") warn(envelope.clientTimestamp!!, "[handleAdminRemoteDelete] Invalid admin delete! deleteTime: ${envelope.serverTimestamp!!}, targetTime: ${targetMessage.serverTimestamp}, deleteAuthor: ${senderRecipient.id}, targetAuthor: ${targetMessage.fromRecipient.id}, isAdmin: ${groupRecord.isAdmin(senderRecipient)}")
null null
} }
} }
@@ -1627,7 +1627,7 @@ object DataMessageProcessor {
): MessageId? { ): MessageId? {
val targetMessage = SignalDatabase.messages.getMessageFor(targetSentTimestamp, targetAuthor.id) val targetMessage = SignalDatabase.messages.getMessageFor(targetSentTimestamp, targetAuthor.id)
if (targetMessage == null) { if (targetMessage == null) {
warn(envelope.timestamp!!, "[handlePollValidation] Could not find matching message! Putting it in the early message cache. timestamp: $targetSentTimestamp author: ${targetAuthor.id}") warn(envelope.clientTimestamp!!, "[handlePollValidation] Could not find matching message! Putting it in the early message cache. timestamp: $targetSentTimestamp author: ${targetAuthor.id}")
if (earlyMessageCacheEntry != null) { if (earlyMessageCacheEntry != null) {
AppDependencies.earlyMessageCache.store(senderRecipient.id, targetSentTimestamp, earlyMessageCacheEntry) AppDependencies.earlyMessageCache.store(senderRecipient.id, targetSentTimestamp, earlyMessageCacheEntry)
PushProcessEarlyMessagesJob.enqueue() PushProcessEarlyMessagesJob.enqueue()
@@ -1636,22 +1636,22 @@ object DataMessageProcessor {
} }
if (targetMessage.isRemoteDelete) { if (targetMessage.isRemoteDelete) {
warn(envelope.timestamp!!, "[handlePollValidation] Found a matching message, but it's flagged as remotely deleted. timestamp: $targetSentTimestamp author: ${targetAuthor.id}") warn(envelope.clientTimestamp!!, "[handlePollValidation] Found a matching message, but it's flagged as remotely deleted. timestamp: $targetSentTimestamp author: ${targetAuthor.id}")
return null return null
} }
val targetThread = SignalDatabase.threads.getThreadRecord(targetMessage.threadId) val targetThread = SignalDatabase.threads.getThreadRecord(targetMessage.threadId)
if (targetThread == null) { if (targetThread == null) {
warn(envelope.timestamp!!, "[handlePollValidation] Could not find a thread for the message. timestamp: $targetSentTimestamp author: ${targetAuthor.id}") warn(envelope.clientTimestamp!!, "[handlePollValidation] Could not find a thread for the message. timestamp: $targetSentTimestamp author: ${targetAuthor.id}")
return null return null
} }
val groupRecord = SignalDatabase.groups.getGroup(targetThread.recipient.id).orNull() val groupRecord = SignalDatabase.groups.getGroup(targetThread.recipient.id).orNull()
if (groupRecord != null && !groupRecord.members.contains(senderRecipient.id)) { if (groupRecord != null && !groupRecord.members.contains(senderRecipient.id)) {
warn(envelope.timestamp!!, "[handlePollValidation] Sender is not in the group. timestamp: $targetSentTimestamp author: ${targetAuthor.id}") warn(envelope.clientTimestamp!!, "[handlePollValidation] Sender is not in the group. timestamp: $targetSentTimestamp author: ${targetAuthor.id}")
return null return null
} else if (groupRecord == null && senderRecipient.id != targetThread.recipient.id && senderRecipient.id != Recipient.self().id) { } else if (groupRecord == null && senderRecipient.id != targetThread.recipient.id && senderRecipient.id != Recipient.self().id) {
warn(envelope.timestamp!!, "[handlePollValidation] Sender is not a part of the 1:1 thread!") warn(envelope.clientTimestamp!!, "[handlePollValidation] Sender is not a part of the 1:1 thread!")
return null return null
} }

View File

@@ -50,13 +50,13 @@ object EditMessageProcessor {
) { ) {
val editMessage = content.editMessage!! val editMessage = content.editMessage!!
log(envelope.timestamp!!, "[handleEditMessage] Edit message for " + editMessage.targetSentTimestamp) log(envelope.clientTimestamp!!, "[handleEditMessage] Edit message for " + editMessage.targetSentTimestamp)
var targetMessage: MmsMessageRecord? = SignalDatabase.messages.getMessageFor(editMessage.targetSentTimestamp!!, senderRecipient.id) as? MmsMessageRecord var targetMessage: MmsMessageRecord? = SignalDatabase.messages.getMessageFor(editMessage.targetSentTimestamp!!, senderRecipient.id) as? MmsMessageRecord
val targetThreadRecipient: Recipient? = if (targetMessage != null) SignalDatabase.threads.getRecipientForThreadId(targetMessage.threadId) else null val targetThreadRecipient: Recipient? = if (targetMessage != null) SignalDatabase.threads.getRecipientForThreadId(targetMessage.threadId) else null
if (targetMessage == null || targetThreadRecipient == null) { if (targetMessage == null || targetThreadRecipient == null) {
warn(envelope.timestamp!!, "[handleEditMessage] Could not find matching message! timestamp: ${editMessage.targetSentTimestamp} author: ${senderRecipient.id}") warn(envelope.clientTimestamp!!, "[handleEditMessage] Could not find matching message! timestamp: ${editMessage.targetSentTimestamp} author: ${senderRecipient.id}")
if (earlyMessageCacheEntry != null) { if (earlyMessageCacheEntry != null) {
AppDependencies.earlyMessageCache.store(senderRecipient.id, editMessage.targetSentTimestamp!!, earlyMessageCacheEntry) AppDependencies.earlyMessageCache.store(senderRecipient.id, editMessage.targetSentTimestamp!!, earlyMessageCacheEntry)
@@ -78,12 +78,12 @@ object EditMessageProcessor {
val validTarget = !originalMessage.isViewOnce && !originalMessage.hasAudio() && !originalMessage.hasSharedContact() val validTarget = !originalMessage.isViewOnce && !originalMessage.hasAudio() && !originalMessage.hasSharedContact()
if (!validTiming || !validAuthor || !validGroup || !validTarget) { if (!validTiming || !validAuthor || !validGroup || !validTarget) {
warn(envelope.timestamp!!, "[handleEditMessage] Invalid message edit! editTime: ${envelope.serverTimestamp}, targetTime: ${originalMessage.serverTimestamp}, editAuthor: ${senderRecipient.id}, targetAuthor: ${originalMessage.fromRecipient.id}, editThread: ${threadRecipient.id}, targetThread: ${targetThreadRecipient.id}, validity: (timing: $validTiming, author: $validAuthor, group: $validGroup, target: $validTarget)") warn(envelope.clientTimestamp!!, "[handleEditMessage] Invalid message edit! editTime: ${envelope.serverTimestamp}, targetTime: ${originalMessage.serverTimestamp}, editAuthor: ${senderRecipient.id}, targetAuthor: ${originalMessage.fromRecipient.id}, editThread: ${threadRecipient.id}, targetThread: ${targetThreadRecipient.id}, validity: (timing: $validTiming, author: $validAuthor, group: $validGroup, target: $validTarget)")
return return
} }
if (groupId != null && MessageContentProcessor.handleGv2PreProcessing(context, envelope.timestamp!!, content, metadata, groupId, message.groupV2!!, senderRecipient) == MessageContentProcessor.Gv2PreProcessResult.IGNORE) { if (groupId != null && MessageContentProcessor.handleGv2PreProcessing(context, envelope.clientTimestamp!!, content, metadata, groupId, message.groupV2!!, senderRecipient) == MessageContentProcessor.Gv2PreProcessResult.IGNORE) {
warn(envelope.timestamp!!, "[handleEditMessage] Group processor indicated we should ignore this.") warn(envelope.clientTimestamp!!, "[handleEditMessage] Group processor indicated we should ignore this.")
return return
} }
@@ -187,8 +187,8 @@ object EditMessageProcessor {
val textMessage = IncomingMessage( val textMessage = IncomingMessage(
type = MessageType.NORMAL, type = MessageType.NORMAL,
from = senderRecipientId, from = senderRecipientId,
sentTimeMillis = envelope.timestamp!!, sentTimeMillis = envelope.clientTimestamp!!,
serverTimeMillis = envelope.timestamp!!, serverTimeMillis = envelope.clientTimestamp!!,
receivedTimeMillis = targetMessage.dateReceived, receivedTimeMillis = targetMessage.dateReceived,
body = message.body, body = message.body,
groupId = groupId, groupId = groupId,

View File

@@ -291,8 +291,8 @@ class IncomingMessageObserver(
null null
} }
Envelope.Type.PREKEY_BUNDLE, Envelope.Type.PREKEY_MESSAGE,
Envelope.Type.CIPHERTEXT, Envelope.Type.DOUBLE_RATCHET,
Envelope.Type.UNIDENTIFIED_SENDER, Envelope.Type.UNIDENTIFIED_SENDER,
Envelope.Type.PLAINTEXT_CONTENT -> { Envelope.Type.PLAINTEXT_CONTENT -> {
SignalTrace.beginSection("IncomingMessageObserver#processMessage") SignalTrace.beginSection("IncomingMessageObserver#processMessage")
@@ -343,7 +343,7 @@ class IncomingMessageObserver(
jobs += PushProcessMessageErrorJob( jobs += PushProcessMessageErrorJob(
result.toMessageState(), result.toMessageState(),
result.errorMetadata.toExceptionMetadata(), result.errorMetadata.toExceptionMetadata(),
result.envelope.timestamp!! result.envelope.clientTimestamp!!
) )
AppDependencies.jobManager.startChain(jobs) AppDependencies.jobManager.startChain(jobs)
@@ -369,9 +369,9 @@ class IncomingMessageObserver(
val senderId = RecipientId.from(serviceId) val senderId = RecipientId.from(serviceId)
Log.i(TAG, "Received server receipt. Sender: $senderId, Device: ${envelope.sourceDevice}, Timestamp: ${envelope.timestamp}") Log.i(TAG, "Received server receipt. Sender: $senderId, Device: ${envelope.sourceDeviceId}, Timestamp: ${envelope.clientTimestamp}")
SignalDatabase.messages.incrementDeliveryReceiptCount(envelope.timestamp!!, senderId, System.currentTimeMillis()) SignalDatabase.messages.incrementDeliveryReceiptCount(envelope.clientTimestamp!!, senderId, System.currentTimeMillis())
SignalDatabase.messageLog.deleteEntryForRecipient(envelope.timestamp!!, senderId, envelope.sourceDevice!!) SignalDatabase.messageLog.deleteEntryForRecipient(envelope.clientTimestamp!!, senderId, envelope.sourceDeviceId!!)
} }
private fun MessageDecryptor.Result.toMessageState(): MessageState { private fun MessageDecryptor.Result.toMessageState(): MessageState {

View File

@@ -350,11 +350,11 @@ open class MessageContentProcessor(private val context: Context) {
val earlyCacheEntries: List<EarlyMessageCacheEntry>? = AppDependencies val earlyCacheEntries: List<EarlyMessageCacheEntry>? = AppDependencies
.earlyMessageCache .earlyMessageCache
.retrieve(senderRecipient.id, envelope.timestamp!!) .retrieve(senderRecipient.id, envelope.clientTimestamp!!)
.orNull() .orNull()
if (!processingEarlyContent && earlyCacheEntries != null) { if (!processingEarlyContent && earlyCacheEntries != null) {
log(envelope.timestamp!!, "Found " + earlyCacheEntries.size + " dependent item(s) that were retrieved earlier. Processing.") log(envelope.clientTimestamp!!, "Found " + earlyCacheEntries.size + " dependent item(s) that were retrieved earlier. Processing.")
for (entry in earlyCacheEntries) { for (entry in earlyCacheEntries) {
handleMessage(senderRecipient, entry.envelope, entry.content, entry.metadata, entry.serverDeliveredTimestamp, processingEarlyContent = true, localMetric = null, batchCache) handleMessage(senderRecipient, entry.envelope, entry.content, entry.metadata, entry.serverDeliveredTimestamp, processingEarlyContent = true, localMetric = null, batchCache)
} }
@@ -442,14 +442,14 @@ open class MessageContentProcessor(private val context: Context) {
val threadRecipient = getMessageDestination(content, senderRecipient) val threadRecipient = getMessageDestination(content, senderRecipient)
if (shouldIgnore(content, senderRecipient, threadRecipient)) { if (shouldIgnore(content, senderRecipient, threadRecipient)) {
log(envelope.timestamp!!, "Ignoring message.") log(envelope.clientTimestamp!!, "Ignoring message.")
return return
} }
val pending: PendingRetryReceiptModel? = AppDependencies.pendingRetryReceiptCache.get(senderRecipient.id, envelope.timestamp!!) val pending: PendingRetryReceiptModel? = AppDependencies.pendingRetryReceiptCache.get(senderRecipient.id, envelope.clientTimestamp!!)
val receivedTime: Long = handlePendingRetry(pending, envelope.timestamp!!, threadRecipient) val receivedTime: Long = handlePendingRetry(pending, envelope.clientTimestamp!!, threadRecipient)
log(envelope.timestamp!!, "Beginning message processing. Sender: " + formatSender(senderRecipient.id, metadata.sourceServiceId, metadata.sourceDeviceId)) log(envelope.clientTimestamp!!, "Beginning message processing. Sender: " + formatSender(senderRecipient.id, metadata.sourceServiceId, metadata.sourceDeviceId))
localMetric?.onPreProcessComplete() localMetric?.onPreProcessComplete()
when { when {
content.dataMessage != null -> { content.dataMessage != null -> {
@@ -482,12 +482,12 @@ open class MessageContentProcessor(private val context: Context) {
} }
content.callMessage != null -> { content.callMessage != null -> {
log(envelope.timestamp!!, "Got call message...") log(envelope.clientTimestamp!!, "Got call message...")
val message: CallMessage = content.callMessage!! val message: CallMessage = content.callMessage!!
if (message.destinationDeviceId != null && message.destinationDeviceId != SignalStore.account.deviceId) { if (message.destinationDeviceId != null && message.destinationDeviceId != SignalStore.account.deviceId) {
log(envelope.timestamp!!, "Ignoring call message that is not for this device! intended: ${message.destinationDeviceId}, this: ${SignalStore.account.deviceId}") log(envelope.clientTimestamp!!, "Ignoring call message that is not for this device! intended: ${message.destinationDeviceId}, this: ${SignalStore.account.deviceId}")
return return
} }
@@ -541,12 +541,12 @@ open class MessageContentProcessor(private val context: Context) {
} }
else -> { else -> {
warn(envelope.timestamp!!, "Got unrecognized message!") warn(envelope.clientTimestamp!!, "Got unrecognized message!")
} }
} }
if (pending != null) { if (pending != null) {
warn(envelope.timestamp!!, "Pending retry was processed. Deleting.") warn(envelope.clientTimestamp!!, "Pending retry was processed. Deleting.")
AppDependencies.pendingRetryReceiptCache.delete(pending) AppDependencies.pendingRetryReceiptCache.delete(pending)
} }
} }
@@ -565,7 +565,7 @@ open class MessageContentProcessor(private val context: Context) {
val threadId: Long = if (typingMessage.groupId != null) { val threadId: Long = if (typingMessage.groupId != null) {
val groupId = GroupId.push(typingMessage.groupId!!) val groupId = GroupId.push(typingMessage.groupId!!)
if (!SignalDatabase.groups.isCurrentMember(groupId, senderRecipient.id)) { if (!SignalDatabase.groups.isCurrentMember(groupId, senderRecipient.id)) {
warn(envelope.timestamp!!, "Seen typing indicator for non-member " + senderRecipient.id) warn(envelope.clientTimestamp!!, "Seen typing indicator for non-member " + senderRecipient.id)
return return
} }
@@ -576,7 +576,7 @@ open class MessageContentProcessor(private val context: Context) {
} }
if (threadId <= 0) { if (threadId <= 0) {
warn(envelope.timestamp!!, "Couldn't find a matching thread for a typing message.") warn(envelope.clientTimestamp!!, "Couldn't find a matching thread for a typing message.")
return return
} }
@@ -591,19 +591,19 @@ open class MessageContentProcessor(private val context: Context) {
private fun handleRetryReceipt(envelope: Envelope, metadata: EnvelopeMetadata, decryptionErrorMessage: DecryptionErrorMessage, senderRecipient: Recipient) { private fun handleRetryReceipt(envelope: Envelope, metadata: EnvelopeMetadata, decryptionErrorMessage: DecryptionErrorMessage, senderRecipient: Recipient) {
if (!RemoteConfig.retryReceipts) { if (!RemoteConfig.retryReceipts) {
warn(envelope.timestamp!!, "[RetryReceipt] Feature flag disabled, skipping retry receipt.") warn(envelope.clientTimestamp!!, "[RetryReceipt] Feature flag disabled, skipping retry receipt.")
return return
} }
if (decryptionErrorMessage.deviceId != SignalStore.account.deviceId) { if (decryptionErrorMessage.deviceId != SignalStore.account.deviceId) {
log(envelope.timestamp!!, "[RetryReceipt] Received a DecryptionErrorMessage targeting a linked device. Ignoring.") log(envelope.clientTimestamp!!, "[RetryReceipt] Received a DecryptionErrorMessage targeting a linked device. Ignoring.")
return return
} }
val sentTimestamp = decryptionErrorMessage.timestamp val sentTimestamp = decryptionErrorMessage.timestamp
warn(envelope.timestamp!!, "[RetryReceipt] Received a retry receipt from ${formatSender(senderRecipient.id, metadata.sourceServiceId, metadata.sourceDeviceId)} for message with timestamp $sentTimestamp.") warn(envelope.clientTimestamp!!, "[RetryReceipt] Received a retry receipt from ${formatSender(senderRecipient.id, metadata.sourceServiceId, metadata.sourceDeviceId)} for message with timestamp $sentTimestamp.")
if (!senderRecipient.hasServiceId) { if (!senderRecipient.hasServiceId) {
warn(envelope.timestamp!!, "[RetryReceipt] Requester ${senderRecipient.id} somehow has no UUID! timestamp: $sentTimestamp") warn(envelope.clientTimestamp!!, "[RetryReceipt] Requester ${senderRecipient.id} somehow has no UUID! timestamp: $sentTimestamp")
return return
} }
@@ -626,18 +626,18 @@ open class MessageContentProcessor(private val context: Context) {
val relatedMessage = findRetryReceiptRelatedMessage(messageLogEntry, sentTimestamp) val relatedMessage = findRetryReceiptRelatedMessage(messageLogEntry, sentTimestamp)
if (relatedMessage == null) { if (relatedMessage == null) {
warn(envelope.timestamp!!, "[RetryReceipt-SK] The related message could not be found! There shouldn't be any sender key resends where we can't find the related message. Skipping.") warn(envelope.clientTimestamp!!, "[RetryReceipt-SK] The related message could not be found! There shouldn't be any sender key resends where we can't find the related message. Skipping.")
return return
} }
val threadRecipient = SignalDatabase.threads.getRecipientForThreadId(relatedMessage.threadId) val threadRecipient = SignalDatabase.threads.getRecipientForThreadId(relatedMessage.threadId)
if (threadRecipient == null) { if (threadRecipient == null) {
warn(envelope.timestamp!!, "[RetryReceipt-SK] Could not find a thread recipient! Skipping.") warn(envelope.clientTimestamp!!, "[RetryReceipt-SK] Could not find a thread recipient! Skipping.")
return return
} }
if (!threadRecipient.isPushV2Group && !threadRecipient.isDistributionList) { if (!threadRecipient.isPushV2Group && !threadRecipient.isDistributionList) {
warn(envelope.timestamp!!, "[RetryReceipt-SK] Thread recipient is not a V2 group or distribution list! Skipping.") warn(envelope.clientTimestamp!!, "[RetryReceipt-SK] Thread recipient is not a V2 group or distribution list! Skipping.")
return return
} }
@@ -661,7 +661,7 @@ open class MessageContentProcessor(private val context: Context) {
SignalDatabase.senderKeyShared.delete(distributionId, setOf(requesterAddress)) SignalDatabase.senderKeyShared.delete(distributionId, setOf(requesterAddress))
if (messageLogEntry != null) { if (messageLogEntry != null) {
warn(envelope.timestamp!!, "[RetryReceipt-SK] Found MSL entry for ${requester.id} ($requesterAddress) with timestamp $sentTimestamp. Scheduling a resend.") warn(envelope.clientTimestamp!!, "[RetryReceipt-SK] Found MSL entry for ${requester.id} ($requesterAddress) with timestamp $sentTimestamp. Scheduling a resend.")
AppDependencies.jobManager.add( AppDependencies.jobManager.add(
ResendMessageJob( ResendMessageJob(
messageLogEntry.recipientId, messageLogEntry.recipientId,
@@ -674,7 +674,7 @@ open class MessageContentProcessor(private val context: Context) {
) )
) )
} else { } else {
warn(envelope.timestamp!!, "[RetryReceipt-SK] Unable to find MSL entry for ${requester.id} ($requesterAddress) with timestamp $sentTimestamp for ${if (groupId != null) "group $groupId" else "distribution list"}. Scheduling a job to send them the SenderKeyDistributionMessage. Membership will be checked there.") warn(envelope.clientTimestamp!!, "[RetryReceipt-SK] Unable to find MSL entry for ${requester.id} ($requesterAddress) with timestamp $sentTimestamp for ${if (groupId != null) "group $groupId" else "distribution list"}. Scheduling a job to send them the SenderKeyDistributionMessage. Membership will be checked there.")
AppDependencies.jobManager.add(SenderKeyDistributionSendJob(requester.id, threadRecipient.id)) AppDependencies.jobManager.add(SenderKeyDistributionSendJob(requester.id, threadRecipient.id))
} }
} }
@@ -683,24 +683,24 @@ open class MessageContentProcessor(private val context: Context) {
var archivedSession = false var archivedSession = false
if (ServiceId.parseOrNull(envelope.destinationServiceId, envelope.destinationServiceIdBinary) is ServiceId.PNI) { if (ServiceId.parseOrNull(envelope.destinationServiceId, envelope.destinationServiceIdBinary) is ServiceId.PNI) {
warn(envelope.timestamp!!, "[RetryReceipt-I] Destination is our PNI. Ignoring.") warn(envelope.clientTimestamp!!, "[RetryReceipt-I] Destination is our PNI. Ignoring.")
return return
} }
if (decryptionErrorMessage.ratchetKey.isPresent) { if (decryptionErrorMessage.ratchetKey.isPresent) {
if (ratchetKeyMatches(requester, metadata.sourceDeviceId, decryptionErrorMessage.ratchetKey.get())) { if (ratchetKeyMatches(requester, metadata.sourceDeviceId, decryptionErrorMessage.ratchetKey.get())) {
warn(envelope.timestamp!!, "[RetryReceipt-I] Ratchet key matches. Archiving the session.") warn(envelope.clientTimestamp!!, "[RetryReceipt-I] Ratchet key matches. Archiving the session.")
AppDependencies.protocolStore.aci().sessions().archiveSession(requester.requireServiceId(), metadata.sourceDeviceId) AppDependencies.protocolStore.aci().sessions().archiveSession(requester.requireServiceId(), metadata.sourceDeviceId)
archivedSession = true archivedSession = true
} else { } else {
log(envelope.timestamp!!, "[RetryReceipt-I] Ratchet key does not match. Leaving the session as-is.") log(envelope.clientTimestamp!!, "[RetryReceipt-I] Ratchet key does not match. Leaving the session as-is.")
} }
} else { } else {
warn(envelope.timestamp!!, "[RetryReceipt-I] Missing ratchet key! Can't archive session.") warn(envelope.clientTimestamp!!, "[RetryReceipt-I] Missing ratchet key! Can't archive session.")
} }
if (messageLogEntry != null) { if (messageLogEntry != null) {
warn(envelope.timestamp!!, "[RetryReceipt-I] Found an entry in the MSL. Resending.") warn(envelope.clientTimestamp!!, "[RetryReceipt-I] Found an entry in the MSL. Resending.")
AppDependencies.jobManager.add( AppDependencies.jobManager.add(
ResendMessageJob( ResendMessageJob(
messageLogEntry.recipientId, messageLogEntry.recipientId,
@@ -713,10 +713,10 @@ open class MessageContentProcessor(private val context: Context) {
) )
) )
} else if (archivedSession) { } else if (archivedSession) {
warn(envelope.timestamp!!, "[RetryReceipt-I] Could not find an entry in the MSL, but we archived the session, so we're sending a null message to complete the reset.") warn(envelope.clientTimestamp!!, "[RetryReceipt-I] Could not find an entry in the MSL, but we archived the session, so we're sending a null message to complete the reset.")
AppDependencies.jobManager.add(NullMessageSendJob(requester.id)) AppDependencies.jobManager.add(NullMessageSendJob(requester.id))
} else { } else {
warn(envelope.timestamp!!, "[RetryReceipt-I] Could not find an entry in the MSL. Skipping.") warn(envelope.clientTimestamp!!, "[RetryReceipt-I] Could not find an entry in the MSL. Skipping.")
} }
} }

View File

@@ -142,7 +142,7 @@ object MessageDecryptor {
val followUpOperations: MutableList<FollowUpOperation> = mutableListOf() val followUpOperations: MutableList<FollowUpOperation> = mutableListOf()
if (envelope.type == Envelope.Type.PREKEY_BUNDLE) { if (envelope.type == Envelope.Type.PREKEY_MESSAGE) {
Log.i(TAG, "${logPrefix(envelope)} Prekey message. Scheduling a prekey sync job.") Log.i(TAG, "${logPrefix(envelope)} Prekey message. Scheduling a prekey sync job.")
followUpOperations += FollowUpOperation { followUpOperations += FollowUpOperation {
PreKeysSyncJob.create().asChain() PreKeysSyncJob.create().asChain()
@@ -164,7 +164,7 @@ object MessageDecryptor {
envelope.newBuilder() envelope.newBuilder()
.sourceServiceId(if (BuildConfig.USE_STRING_ID) cipherResult.metadata.sourceServiceId.toString() else null) .sourceServiceId(if (BuildConfig.USE_STRING_ID) cipherResult.metadata.sourceServiceId.toString() else null)
.sourceServiceIdBinary(if (RemoteConfig.useBinaryId) cipherResult.metadata.sourceServiceId.toByteString() else null) .sourceServiceIdBinary(if (RemoteConfig.useBinaryId) cipherResult.metadata.sourceServiceId.toByteString() else null)
.sourceDevice(cipherResult.metadata.sourceDeviceId) .sourceDeviceId(cipherResult.metadata.sourceDeviceId)
.build() .build()
} else { } else {
envelope envelope
@@ -255,7 +255,7 @@ object MessageDecryptor {
followUpOperations += FollowUpOperation { followUpOperations += FollowUpOperation {
Recipient.external(e.sender)?.let { Recipient.external(e.sender)?.let {
AutomaticSessionResetJob(it.id, e.senderDevice, envelope.timestamp!!).asChain() AutomaticSessionResetJob(it.id, e.senderDevice, envelope.clientTimestamp!!).asChain()
} ?: null.logW(TAG, "${logPrefix(envelope, e)} Failed to create a recipient with the provided identifier!") } ?: null.logW(TAG, "${logPrefix(envelope, e)} Failed to create a recipient with the provided identifier!")
} }
@@ -276,7 +276,7 @@ object MessageDecryptor {
} }
is SelfSendException -> { is SelfSendException -> {
Log.i(TAG, "[${envelope.timestamp}] Dropping sealed sender message from self!", e) Log.i(TAG, "[${envelope.clientTimestamp}] Dropping sealed sender message from self!", e)
Result.Ignore(envelope, serverDeliveredTimestamp, followUpOperations.toUnmodifiableList()) Result.Ignore(envelope, serverDeliveredTimestamp, followUpOperations.toUnmodifiableList())
} }
@@ -320,7 +320,7 @@ object MessageDecryptor {
Log.w(TAG, "${logPrefix(envelope)} Decryption error for a sync message! Enqueuing a session reset job.", true) Log.w(TAG, "${logPrefix(envelope)} Decryption error for a sync message! Enqueuing a session reset job.", true)
followUpOperations += FollowUpOperation { followUpOperations += FollowUpOperation {
AutomaticSessionResetJob(sender.id, senderDevice, envelope.timestamp!!).asChain() AutomaticSessionResetJob(sender.id, senderDevice, envelope.clientTimestamp!!).asChain()
} }
return Result.Ignore(envelope, serverDeliveredTimestamp, followUpOperations) return Result.Ignore(envelope, serverDeliveredTimestamp, followUpOperations)
@@ -355,7 +355,7 @@ object MessageDecryptor {
// Note: if the message is sealed sender, it's envelope type will be UNIDENTIFIED_SENDER. The only way we can currently check if the error is // Note: if the message is sealed sender, it's envelope type will be UNIDENTIFIED_SENDER. The only way we can currently check if the error is
// prekey-related in that situation is using a string match. // prekey-related in that situation is using a string match.
if (envelope.type == Envelope.Type.PREKEY_BUNDLE || protocolException.message?.lowercase()?.contains("prekey") == true) { if (envelope.type == Envelope.Type.PREKEY_MESSAGE || protocolException.message?.lowercase()?.contains("prekey") == true) {
Log.w(TAG, "${logPrefix(envelope, senderServiceId)} Got a decryption error on a prekey message. Forcing a prekey rotation before requesting the retry.", true) Log.w(TAG, "${logPrefix(envelope, senderServiceId)} Got a decryption error on a prekey message. Forcing a prekey rotation before requesting the retry.", true)
PreKeysSyncJob.create(forceRotationRequested = true).asChain().then(retryJob) PreKeysSyncJob.create(forceRotationRequested = true).asChain().then(retryJob)
} else { } else {
@@ -392,7 +392,7 @@ object MessageDecryptor {
return@FollowUpOperation null return@FollowUpOperation null
} }
AppDependencies.pendingRetryReceiptCache.insert(sender.id, senderDevice, envelope.timestamp!!, receivedTimestamp, threadId) AppDependencies.pendingRetryReceiptCache.insert(sender.id, senderDevice, envelope.clientTimestamp!!, receivedTimestamp, threadId)
AppDependencies.pendingRetryReceiptManager.scheduleIfNecessary() AppDependencies.pendingRetryReceiptManager.scheduleIfNecessary()
null null
} }
@@ -491,26 +491,26 @@ object MessageDecryptor {
} }
private fun logPrefix(envelope: Envelope): String { private fun logPrefix(envelope: Envelope): String {
return logPrefix(envelope.timestamp!!, ServiceId.parseOrNull(envelope.sourceServiceId, envelope.sourceServiceIdBinary)?.logString() ?: "<sealed>", envelope.sourceDevice) return logPrefix(envelope.clientTimestamp!!, ServiceId.parseOrNull(envelope.sourceServiceId, envelope.sourceServiceIdBinary)?.logString() ?: "<sealed>", envelope.sourceDeviceId)
} }
private fun logPrefix(envelope: Envelope, sender: ServiceId?): String { private fun logPrefix(envelope: Envelope, sender: ServiceId?): String {
return logPrefix(envelope.timestamp!!, sender?.logString() ?: "?", envelope.sourceDevice) return logPrefix(envelope.clientTimestamp!!, sender?.logString() ?: "?", envelope.sourceDeviceId)
} }
private fun logPrefix(envelope: Envelope, sender: String): String { private fun logPrefix(envelope: Envelope, sender: String): String {
return logPrefix(envelope.timestamp!!, ServiceId.parseOrNull(sender)?.logString() ?: "?", envelope.sourceDevice) return logPrefix(envelope.clientTimestamp!!, ServiceId.parseOrNull(sender)?.logString() ?: "?", envelope.sourceDeviceId)
} }
private fun logPrefix(envelope: Envelope, cipherResult: SignalServiceCipherResult): String { private fun logPrefix(envelope: Envelope, cipherResult: SignalServiceCipherResult): String {
return logPrefix(envelope.timestamp!!, cipherResult.metadata.sourceServiceId.logString(), cipherResult.metadata.sourceDeviceId) return logPrefix(envelope.clientTimestamp!!, cipherResult.metadata.sourceServiceId.logString(), cipherResult.metadata.sourceDeviceId)
} }
private fun logPrefix(envelope: Envelope, exception: ProtocolException): String { private fun logPrefix(envelope: Envelope, exception: ProtocolException): String {
return if (exception.sender != null) { return if (exception.sender != null) {
logPrefix(envelope.timestamp!!, ServiceId.parseOrNull(exception.sender)?.logString() ?: "?", exception.senderDevice) logPrefix(envelope.clientTimestamp!!, ServiceId.parseOrNull(exception.sender)?.logString() ?: "?", exception.senderDevice)
} else { } else {
logPrefix(envelope.timestamp!!, ServiceId.parseOrNull(envelope.sourceServiceId, envelope.sourceServiceIdBinary).toString(), envelope.sourceDevice) logPrefix(envelope.clientTimestamp!!, ServiceId.parseOrNull(envelope.sourceServiceId, envelope.sourceServiceIdBinary).toString(), envelope.sourceDeviceId)
} }
} }
@@ -531,7 +531,7 @@ object MessageDecryptor {
envelopeType = envelope.type!!.value.toCiphertextMessageType() envelopeType = envelope.type!!.value.toCiphertextMessageType()
} }
val decryptionErrorMessage: DecryptionErrorMessage = DecryptionErrorMessage.forOriginalMessage(originalContent, envelopeType, envelope.timestamp!!, protocolException.senderDevice) val decryptionErrorMessage: DecryptionErrorMessage = DecryptionErrorMessage.forOriginalMessage(originalContent, envelopeType, envelope.clientTimestamp!!, protocolException.senderDevice)
val groupId: GroupId? = protocolException.parseGroupId(envelope) val groupId: GroupId? = protocolException.parseGroupId(envelope)
return SendRetryReceiptJob(sender.id, Optional.ofNullable(groupId), decryptionErrorMessage) return SendRetryReceiptJob(sender.id, Optional.ofNullable(groupId), decryptionErrorMessage)
} }
@@ -541,7 +541,7 @@ object MessageDecryptor {
try { try {
GroupId.push(this.groupId.get()) GroupId.push(this.groupId.get())
} catch (e: BadGroupIdException) { } catch (e: BadGroupIdException) {
Log.w(TAG, "[${envelope.timestamp}] Bad groupId!", true) Log.w(TAG, "[${envelope.clientTimestamp}] Bad groupId!", true)
null null
} }
} else { } else {
@@ -551,8 +551,8 @@ object MessageDecryptor {
private fun Int.toCiphertextMessageType(): Int { private fun Int.toCiphertextMessageType(): Int {
return when (this) { return when (this) {
Envelope.Type.CIPHERTEXT.value -> CiphertextMessage.WHISPER_TYPE Envelope.Type.DOUBLE_RATCHET.value -> CiphertextMessage.WHISPER_TYPE
Envelope.Type.PREKEY_BUNDLE.value -> CiphertextMessage.PREKEY_TYPE Envelope.Type.PREKEY_MESSAGE.value -> CiphertextMessage.PREKEY_TYPE
Envelope.Type.UNIDENTIFIED_SENDER.value -> CiphertextMessage.SENDERKEY_TYPE Envelope.Type.UNIDENTIFIED_SENDER.value -> CiphertextMessage.SENDERKEY_TYPE
Envelope.Type.PLAINTEXT_CONTENT.value -> CiphertextMessage.PLAINTEXT_CONTENT_TYPE Envelope.Type.PLAINTEXT_CONTENT.value -> CiphertextMessage.PLAINTEXT_CONTENT_TYPE
else -> CiphertextMessage.WHISPER_TYPE else -> CiphertextMessage.WHISPER_TYPE

View File

@@ -31,7 +31,7 @@ object ReceiptMessageProcessor {
ReceiptMessage.Type.DELIVERY -> handleDeliveryReceipt(envelope, metadata, receiptMessage, senderRecipient.id, batchCache) ReceiptMessage.Type.DELIVERY -> handleDeliveryReceipt(envelope, metadata, receiptMessage, senderRecipient.id, batchCache)
ReceiptMessage.Type.READ -> handleReadReceipt(context, senderRecipient.id, envelope, metadata, receiptMessage, earlyMessageCacheEntry, batchCache) ReceiptMessage.Type.READ -> handleReadReceipt(context, senderRecipient.id, envelope, metadata, receiptMessage, earlyMessageCacheEntry, batchCache)
ReceiptMessage.Type.VIEWED -> handleViewedReceipt(context, envelope, metadata, receiptMessage, senderRecipient.id, earlyMessageCacheEntry) ReceiptMessage.Type.VIEWED -> handleViewedReceipt(context, envelope, metadata, receiptMessage, senderRecipient.id, earlyMessageCacheEntry)
else -> warn(envelope.timestamp!!, "Unknown recipient message type ${receiptMessage.type}") else -> warn(envelope.clientTimestamp!!, "Unknown recipient message type ${receiptMessage.type}")
} }
} }
@@ -43,15 +43,15 @@ object ReceiptMessageProcessor {
senderRecipientId: RecipientId, senderRecipientId: RecipientId,
batchCache: BatchCache batchCache: BatchCache
) { ) {
log(envelope.timestamp!!, "Processing delivery receipts. Sender: $senderRecipientId, Device: ${metadata.sourceDeviceId}, Timestamps: ${deliveryReceipt.timestamp.joinToString(", ")}") log(envelope.clientTimestamp!!, "Processing delivery receipts. Sender: $senderRecipientId, Device: ${metadata.sourceDeviceId}, Timestamps: ${deliveryReceipt.timestamp.joinToString(", ")}")
val stopwatch: Stopwatch? = if (VERBOSE) Stopwatch("delivery-receipt", decimalPlaces = 2) else null val stopwatch: Stopwatch? = if (VERBOSE) Stopwatch("delivery-receipt", decimalPlaces = 2) else null
SignalTrace.beginSection("ReceiptMessageProcessor#incrementDeliveryReceiptCounts") SignalTrace.beginSection("ReceiptMessageProcessor#incrementDeliveryReceiptCounts")
val missingTargetTimestamps: Set<Long> = SignalDatabase.messages.incrementDeliveryReceiptCounts(deliveryReceipt.timestamp, senderRecipientId, envelope.timestamp!!, stopwatch, batchCache.deliveryReceiptLookupCache) val missingTargetTimestamps: Set<Long> = SignalDatabase.messages.incrementDeliveryReceiptCounts(deliveryReceipt.timestamp, senderRecipientId, envelope.clientTimestamp!!, stopwatch, batchCache.deliveryReceiptLookupCache)
SignalTrace.endSection() SignalTrace.endSection()
for (targetTimestamp in missingTargetTimestamps) { for (targetTimestamp in missingTargetTimestamps) {
warn(envelope.timestamp!!, "[handleDeliveryReceipt] Could not find matching message! targetTimestamp: $targetTimestamp, receiptAuthor: $senderRecipientId") warn(envelope.clientTimestamp!!, "[handleDeliveryReceipt] Could not find matching message! targetTimestamp: $targetTimestamp, receiptAuthor: $senderRecipientId")
// Early delivery receipts are special-cased in the database methods // Early delivery receipts are special-cased in the database methods
} }
@@ -79,21 +79,21 @@ object ReceiptMessageProcessor {
batchCache: BatchCache batchCache: BatchCache
) { ) {
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) { if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
log(envelope.timestamp!!, "Ignoring read receipts for IDs: " + readReceipt.timestamp.joinToString(", ")) log(envelope.clientTimestamp!!, "Ignoring read receipts for IDs: " + readReceipt.timestamp.joinToString(", "))
return return
} }
log(envelope.timestamp!!, "Processing read receipts. Sender: $senderRecipientId, Device: ${metadata.sourceDeviceId}, Timestamps: ${readReceipt.timestamp.joinToString(", ")}") log(envelope.clientTimestamp!!, "Processing read receipts. Sender: $senderRecipientId, Device: ${metadata.sourceDeviceId}, Timestamps: ${readReceipt.timestamp.joinToString(", ")}")
SignalTrace.beginSection("ReceiptMessageProcessor#incrementReadReceiptCounts") SignalTrace.beginSection("ReceiptMessageProcessor#incrementReadReceiptCounts")
val missingTargetTimestamps: Set<Long> = SignalDatabase.messages.incrementReadReceiptCounts(readReceipt.timestamp, senderRecipientId, envelope.timestamp!!, batchCache.readReceiptLookupCache) val missingTargetTimestamps: Set<Long> = SignalDatabase.messages.incrementReadReceiptCounts(readReceipt.timestamp, senderRecipientId, envelope.clientTimestamp!!, batchCache.readReceiptLookupCache)
SignalTrace.endSection() SignalTrace.endSection()
if (missingTargetTimestamps.isNotEmpty()) { if (missingTargetTimestamps.isNotEmpty()) {
val selfId = Recipient.self().id val selfId = Recipient.self().id
for (targetTimestamp in missingTargetTimestamps) { for (targetTimestamp in missingTargetTimestamps) {
warn(envelope.timestamp!!, "[handleReadReceipt] Could not find matching message! targetTimestamp: $targetTimestamp, receiptAuthor: $senderRecipientId | Receipt, so associating with message from self ($selfId)") warn(envelope.clientTimestamp!!, "[handleReadReceipt] Could not find matching message! targetTimestamp: $targetTimestamp, receiptAuthor: $senderRecipientId | Receipt, so associating with message from self ($selfId)")
if (earlyMessageCacheEntry != null) { if (earlyMessageCacheEntry != null) {
AppDependencies.earlyMessageCache.store(selfId, targetTimestamp, earlyMessageCacheEntry) AppDependencies.earlyMessageCache.store(selfId, targetTimestamp, earlyMessageCacheEntry)
} }
@@ -117,18 +117,18 @@ object ReceiptMessageProcessor {
val storyViewedReceipts = SignalStore.story.viewedReceiptsEnabled val storyViewedReceipts = SignalStore.story.viewedReceiptsEnabled
if (!readReceipts && !storyViewedReceipts) { if (!readReceipts && !storyViewedReceipts) {
log(envelope.timestamp!!, "Ignoring viewed receipts for IDs: ${viewedReceipt.timestamp.joinToString(", ")}") log(envelope.clientTimestamp!!, "Ignoring viewed receipts for IDs: ${viewedReceipt.timestamp.joinToString(", ")}")
return return
} }
log(envelope.timestamp!!, "Processing viewed receipts. Sender: $senderRecipientId, Device: ${metadata.sourceDeviceId}, Only Stories: ${!readReceipts}, Timestamps: ${viewedReceipt.timestamp.joinToString(", ")}") log(envelope.clientTimestamp!!, "Processing viewed receipts. Sender: $senderRecipientId, Device: ${metadata.sourceDeviceId}, Only Stories: ${!readReceipts}, Timestamps: ${viewedReceipt.timestamp.joinToString(", ")}")
val missingTargetTimestamps: Set<Long> = if (readReceipts && storyViewedReceipts) { val missingTargetTimestamps: Set<Long> = if (readReceipts && storyViewedReceipts) {
SignalDatabase.messages.incrementViewedReceiptCounts(viewedReceipt.timestamp, senderRecipientId, envelope.timestamp!!) SignalDatabase.messages.incrementViewedReceiptCounts(viewedReceipt.timestamp, senderRecipientId, envelope.clientTimestamp!!)
} else if (readReceipts) { } else if (readReceipts) {
SignalDatabase.messages.incrementViewedNonStoryReceiptCounts(viewedReceipt.timestamp, senderRecipientId, envelope.timestamp!!) SignalDatabase.messages.incrementViewedNonStoryReceiptCounts(viewedReceipt.timestamp, senderRecipientId, envelope.clientTimestamp!!)
} else { } else {
SignalDatabase.messages.incrementViewedStoryReceiptCounts(viewedReceipt.timestamp, senderRecipientId, envelope.timestamp!!) SignalDatabase.messages.incrementViewedStoryReceiptCounts(viewedReceipt.timestamp, senderRecipientId, envelope.clientTimestamp!!)
} }
val foundTargetTimestamps: Set<Long> = viewedReceipt.timestamp.toSet() - missingTargetTimestamps.toSet() val foundTargetTimestamps: Set<Long> = viewedReceipt.timestamp.toSet() - missingTargetTimestamps.toSet()
@@ -138,7 +138,7 @@ object ReceiptMessageProcessor {
val selfId = Recipient.self().id val selfId = Recipient.self().id
for (targetTimestamp in missingTargetTimestamps) { for (targetTimestamp in missingTargetTimestamps) {
warn(envelope.timestamp!!, "[handleViewedReceipt] Could not find matching message! targetTimestamp: $targetTimestamp, receiptAuthor: $senderRecipientId | Receipt so associating with message from self ($selfId)") warn(envelope.clientTimestamp!!, "[handleViewedReceipt] Could not find matching message! targetTimestamp: $targetTimestamp, receiptAuthor: $senderRecipientId | Receipt so associating with message from self ($selfId)")
if (earlyMessageCacheEntry != null) { if (earlyMessageCacheEntry != null) {
AppDependencies.earlyMessageCache.store(selfId, targetTimestamp, earlyMessageCacheEntry) AppDependencies.earlyMessageCache.store(selfId, targetTimestamp, earlyMessageCacheEntry)
} }

View File

@@ -33,20 +33,20 @@ object StoryMessageProcessor {
fun process(envelope: Envelope, content: Content, metadata: EnvelopeMetadata, senderRecipient: Recipient, threadRecipient: Recipient) { fun process(envelope: Envelope, content: Content, metadata: EnvelopeMetadata, senderRecipient: Recipient, threadRecipient: Recipient) {
val storyMessage = content.storyMessage!! val storyMessage = content.storyMessage!!
log(envelope.timestamp!!, "Story message.") log(envelope.clientTimestamp!!, "Story message.")
if (threadRecipient.isInactiveGroup) { if (threadRecipient.isInactiveGroup) {
warn(envelope.timestamp!!, "Dropping a group story from a group we're no longer in.") warn(envelope.clientTimestamp!!, "Dropping a group story from a group we're no longer in.")
return return
} }
if (threadRecipient.isGroup && !SignalDatabase.groups.isCurrentMember(threadRecipient.requireGroupId().requirePush(), senderRecipient.id)) { if (threadRecipient.isGroup && !SignalDatabase.groups.isCurrentMember(threadRecipient.requireGroupId().requirePush(), senderRecipient.id)) {
warn(envelope.timestamp!!, "Dropping a group story from a user who's no longer a member.") warn(envelope.clientTimestamp!!, "Dropping a group story from a user who's no longer a member.")
return return
} }
if (!threadRecipient.isGroup && !(senderRecipient.isProfileSharing || senderRecipient.isSystemContact)) { if (!threadRecipient.isGroup && !(senderRecipient.isProfileSharing || senderRecipient.isSystemContact)) {
warn(envelope.timestamp!!, "Dropping story from an untrusted source.") warn(envelope.clientTimestamp!!, "Dropping story from an untrusted source.")
return return
} }
@@ -64,7 +64,7 @@ object StoryMessageProcessor {
val mediaMessage = IncomingMessage( val mediaMessage = IncomingMessage(
type = MessageType.NORMAL, type = MessageType.NORMAL,
from = senderRecipient.id, from = senderRecipient.id,
sentTimeMillis = envelope.timestamp!!, sentTimeMillis = envelope.clientTimestamp!!,
serverTimeMillis = envelope.serverTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!,
receivedTimeMillis = System.currentTimeMillis(), receivedTimeMillis = System.currentTimeMillis(),
storyType = storyType, storyType = storyType,

View File

@@ -162,26 +162,26 @@ object SyncMessageProcessor {
when { when {
syncMessage.sent != null -> handleSynchronizeSentMessage(context, envelope, content, metadata, syncMessage.sent!!, senderRecipient, threadRecipient, earlyMessageCacheEntry) syncMessage.sent != null -> handleSynchronizeSentMessage(context, envelope, content, metadata, syncMessage.sent!!, senderRecipient, threadRecipient, earlyMessageCacheEntry)
syncMessage.request != null -> handleSynchronizeRequestMessage(context, syncMessage.request!!, envelope.timestamp!!) syncMessage.request != null -> handleSynchronizeRequestMessage(context, syncMessage.request!!, envelope.clientTimestamp!!)
syncMessage.read.isNotEmpty() -> handleSynchronizeReadMessage(context, syncMessage.read, envelope.timestamp!!, earlyMessageCacheEntry) syncMessage.read.isNotEmpty() -> handleSynchronizeReadMessage(context, syncMessage.read, envelope.clientTimestamp!!, earlyMessageCacheEntry)
syncMessage.viewed.isNotEmpty() -> handleSynchronizeViewedMessage(context, syncMessage.viewed, envelope.timestamp!!) syncMessage.viewed.isNotEmpty() -> handleSynchronizeViewedMessage(context, syncMessage.viewed, envelope.clientTimestamp!!)
syncMessage.viewOnceOpen != null -> handleSynchronizeViewOnceOpenMessage(context, syncMessage.viewOnceOpen!!, envelope.timestamp!!, earlyMessageCacheEntry) syncMessage.viewOnceOpen != null -> handleSynchronizeViewOnceOpenMessage(context, syncMessage.viewOnceOpen!!, envelope.clientTimestamp!!, earlyMessageCacheEntry)
syncMessage.verified != null -> handleSynchronizeVerifiedMessage(context, syncMessage.verified!!) syncMessage.verified != null -> handleSynchronizeVerifiedMessage(context, syncMessage.verified!!)
syncMessage.stickerPackOperation.isNotEmpty() -> handleSynchronizeStickerPackOperation(syncMessage.stickerPackOperation, envelope.timestamp!!) syncMessage.stickerPackOperation.isNotEmpty() -> handleSynchronizeStickerPackOperation(syncMessage.stickerPackOperation, envelope.clientTimestamp!!)
syncMessage.configuration != null -> handleSynchronizeConfigurationMessage(context, syncMessage.configuration!!, envelope.timestamp!!) syncMessage.configuration != null -> handleSynchronizeConfigurationMessage(context, syncMessage.configuration!!, envelope.clientTimestamp!!)
syncMessage.blocked != null -> handleSynchronizeBlockedListMessage(syncMessage.blocked!!, envelope.timestamp!!) syncMessage.blocked != null -> handleSynchronizeBlockedListMessage(syncMessage.blocked!!, envelope.clientTimestamp!!)
syncMessage.fetchLatest?.type != null -> handleSynchronizeFetchMessage(syncMessage.fetchLatest!!.type!!, envelope.timestamp!!) syncMessage.fetchLatest?.type != null -> handleSynchronizeFetchMessage(syncMessage.fetchLatest!!.type!!, envelope.clientTimestamp!!)
syncMessage.messageRequestResponse != null -> handleSynchronizeMessageRequestResponse(syncMessage.messageRequestResponse!!, envelope.timestamp!!) syncMessage.messageRequestResponse != null -> handleSynchronizeMessageRequestResponse(syncMessage.messageRequestResponse!!, envelope.clientTimestamp!!)
syncMessage.outgoingPayment != null -> handleSynchronizeOutgoingPayment(syncMessage.outgoingPayment!!, envelope.timestamp!!) syncMessage.outgoingPayment != null -> handleSynchronizeOutgoingPayment(syncMessage.outgoingPayment!!, envelope.clientTimestamp!!)
syncMessage.contacts != null -> handleSynchronizeContacts(syncMessage.contacts!!, envelope.timestamp!!) syncMessage.contacts != null -> handleSynchronizeContacts(syncMessage.contacts!!, envelope.clientTimestamp!!)
syncMessage.keys != null -> handleSynchronizeKeys(syncMessage.keys!!, envelope.timestamp!!) syncMessage.keys != null -> handleSynchronizeKeys(syncMessage.keys!!, envelope.clientTimestamp!!)
syncMessage.callEvent != null -> handleSynchronizeCallEvent(syncMessage.callEvent!!, envelope.timestamp!!) syncMessage.callEvent != null -> handleSynchronizeCallEvent(syncMessage.callEvent!!, envelope.clientTimestamp!!)
syncMessage.callLinkUpdate != null -> handleSynchronizeCallLink(syncMessage.callLinkUpdate!!, envelope.timestamp!!) syncMessage.callLinkUpdate != null -> handleSynchronizeCallLink(syncMessage.callLinkUpdate!!, envelope.clientTimestamp!!)
syncMessage.callLogEvent != null -> handleSynchronizeCallLogEvent(syncMessage.callLogEvent!!, envelope.timestamp!!) syncMessage.callLogEvent != null -> handleSynchronizeCallLogEvent(syncMessage.callLogEvent!!, envelope.clientTimestamp!!)
syncMessage.deleteForMe != null -> handleSynchronizeDeleteForMe(context, syncMessage.deleteForMe!!, envelope.timestamp!!, earlyMessageCacheEntry) syncMessage.deleteForMe != null -> handleSynchronizeDeleteForMe(context, syncMessage.deleteForMe!!, envelope.clientTimestamp!!, earlyMessageCacheEntry)
syncMessage.attachmentBackfillRequest != null -> handleSynchronizeAttachmentBackfillRequest(syncMessage.attachmentBackfillRequest!!, envelope.timestamp!!) syncMessage.attachmentBackfillRequest != null -> handleSynchronizeAttachmentBackfillRequest(syncMessage.attachmentBackfillRequest!!, envelope.clientTimestamp!!)
syncMessage.attachmentBackfillResponse != null -> warn(envelope.timestamp!!, "Contains a backfill response, but we don't handle these!") syncMessage.attachmentBackfillResponse != null -> warn(envelope.clientTimestamp!!, "Contains a backfill response, but we don't handle these!")
else -> warn(envelope.timestamp!!, "Contains no known sync types...") else -> warn(envelope.clientTimestamp!!, "Contains no known sync types...")
} }
} }
@@ -196,7 +196,7 @@ object SyncMessageProcessor {
threadRecipient: Recipient, threadRecipient: Recipient,
earlyMessageCacheEntry: EarlyMessageCacheEntry? earlyMessageCacheEntry: EarlyMessageCacheEntry?
) { ) {
log(envelope.timestamp!!, "Processing sent transcript for message with ID ${sent.timestamp!!}") log(envelope.clientTimestamp!!, "Processing sent transcript for message with ID ${sent.timestamp!!}")
try { try {
handlePniIdentityKeys(envelope, sent) handlePniIdentityKeys(envelope, sent)
@@ -212,42 +212,42 @@ object SyncMessageProcessor {
} }
if (sent.isRecipientUpdate == true) { if (sent.isRecipientUpdate == true) {
handleGroupRecipientUpdate(sent, envelope.timestamp!!) handleGroupRecipientUpdate(sent, envelope.clientTimestamp!!)
return return
} }
val dataMessage = if (sent.message != null) { val dataMessage = if (sent.message != null) {
sent.message!! sent.message!!
} else { } else {
warn(envelope.timestamp!!, "Sync message missing nested message to sync") warn(envelope.clientTimestamp!!, "Sync message missing nested message to sync")
return return
} }
val groupId: GroupId.V2? = if (dataMessage.hasGroupContext) GroupId.v2(dataMessage.groupV2!!.groupMasterKey) else null val groupId: GroupId.V2? = if (dataMessage.hasGroupContext) GroupId.v2(dataMessage.groupV2!!.groupMasterKey) else null
if (groupId != null) { if (groupId != null) {
if (MessageContentProcessor.handleGv2PreProcessing(context, envelope.timestamp!!, content, metadata, groupId, dataMessage.groupV2!!, senderRecipient) == MessageContentProcessor.Gv2PreProcessResult.IGNORE) { if (MessageContentProcessor.handleGv2PreProcessing(context, envelope.clientTimestamp!!, content, metadata, groupId, dataMessage.groupV2!!, senderRecipient) == MessageContentProcessor.Gv2PreProcessResult.IGNORE) {
return return
} }
} }
var threadId: Long = -1 var threadId: Long = -1
when { when {
dataMessage.isEndSession -> threadId = handleSynchronizeSentEndSessionMessage(context, sent, envelope.timestamp!!) dataMessage.isEndSession -> threadId = handleSynchronizeSentEndSessionMessage(context, sent, envelope.clientTimestamp!!)
dataMessage.isGroupV2Update -> { dataMessage.isGroupV2Update -> {
handleSynchronizeSentGv2Update(context, envelope, sent) handleSynchronizeSentGv2Update(context, envelope, sent)
threadId = SignalDatabase.threads.getOrCreateThreadIdFor(getSyncMessageDestination(sent)) threadId = SignalDatabase.threads.getOrCreateThreadIdFor(getSyncMessageDestination(sent))
} }
dataMessage.groupCallUpdate != null -> DataMessageProcessor.handleGroupCallUpdateMessage(envelope, senderRecipient.id, groupId) dataMessage.groupCallUpdate != null -> DataMessageProcessor.handleGroupCallUpdateMessage(envelope, senderRecipient.id, groupId)
dataMessage.isEmptyGroupV2Message -> warn(envelope.timestamp!!, "Empty GV2 message! Doing nothing.") dataMessage.isEmptyGroupV2Message -> warn(envelope.clientTimestamp!!, "Empty GV2 message! Doing nothing.")
dataMessage.isExpirationUpdate -> threadId = handleSynchronizeSentExpirationUpdate(sent) dataMessage.isExpirationUpdate -> threadId = handleSynchronizeSentExpirationUpdate(sent)
dataMessage.storyContext != null -> threadId = handleSynchronizeSentStoryReply(sent, envelope.timestamp!!) dataMessage.storyContext != null -> threadId = handleSynchronizeSentStoryReply(sent, envelope.clientTimestamp!!)
dataMessage.reaction != null -> { dataMessage.reaction != null -> {
DataMessageProcessor.handleReaction(context, envelope, dataMessage, senderRecipient.id, earlyMessageCacheEntry) DataMessageProcessor.handleReaction(context, envelope, dataMessage, senderRecipient.id, earlyMessageCacheEntry)
threadId = SignalDatabase.threads.getOrCreateThreadIdFor(getSyncMessageDestination(sent)) threadId = SignalDatabase.threads.getOrCreateThreadIdFor(getSyncMessageDestination(sent))
} }
dataMessage.hasRemoteDelete -> DataMessageProcessor.handleRemoteDelete(context, envelope, dataMessage, senderRecipient.id, earlyMessageCacheEntry) dataMessage.hasRemoteDelete -> DataMessageProcessor.handleRemoteDelete(context, envelope, dataMessage, senderRecipient.id, earlyMessageCacheEntry)
dataMessage.isMediaMessage -> threadId = handleSynchronizeSentMediaMessage(context, sent, envelope.timestamp!!, senderRecipient, threadRecipient) dataMessage.isMediaMessage -> threadId = handleSynchronizeSentMediaMessage(context, sent, envelope.clientTimestamp!!, senderRecipient, threadRecipient)
dataMessage.pollCreate != null -> threadId = handleSynchronizedPollCreate(envelope, dataMessage, sent, senderRecipient) dataMessage.pollCreate != null -> threadId = handleSynchronizedPollCreate(envelope, dataMessage, sent, senderRecipient)
dataMessage.pollVote != null -> { dataMessage.pollVote != null -> {
DataMessageProcessor.handlePollVote(context, envelope, dataMessage, senderRecipient, earlyMessageCacheEntry) DataMessageProcessor.handlePollVote(context, envelope, dataMessage, senderRecipient, earlyMessageCacheEntry)
@@ -264,11 +264,11 @@ object SyncMessageProcessor {
DataMessageProcessor.handleAdminRemoteDelete(context, envelope, dataMessage, senderRecipient, threadRecipient, earlyMessageCacheEntry) DataMessageProcessor.handleAdminRemoteDelete(context, envelope, dataMessage, senderRecipient, threadRecipient, earlyMessageCacheEntry)
threadId = SignalDatabase.threads.getOrCreateThreadIdFor(getSyncMessageDestination(sent)) threadId = SignalDatabase.threads.getOrCreateThreadIdFor(getSyncMessageDestination(sent))
} }
else -> threadId = handleSynchronizeSentTextMessage(sent, envelope.timestamp!!) else -> threadId = handleSynchronizeSentTextMessage(sent, envelope.clientTimestamp!!)
} }
if (groupId != null && SignalDatabase.groups.isUnknownGroup(groupId)) { if (groupId != null && SignalDatabase.groups.isUnknownGroup(groupId)) {
DataMessageProcessor.handleUnknownGroupMessage(envelope.timestamp!!, dataMessage.groupV2!!) DataMessageProcessor.handleUnknownGroupMessage(envelope.clientTimestamp!!, dataMessage.groupV2!!)
} }
if (dataMessage.profileKey.isNotEmpty()) { if (dataMessage.profileKey.isNotEmpty()) {
@@ -284,7 +284,7 @@ object SyncMessageProcessor {
} }
if (SignalStore.rateLimit.needsRecaptcha()) { if (SignalStore.rateLimit.needsRecaptcha()) {
log(envelope.timestamp!!, "Got a sent transcript while in reCAPTCHA mode. Assuming we're good to message again.") log(envelope.clientTimestamp!!, "Got a sent transcript while in reCAPTCHA mode. Assuming we're good to message again.")
RateLimitUtil.retryAllRateLimitedMessages(context) RateLimitUtil.retryAllRateLimitedMessages(context)
} }
@@ -308,16 +308,16 @@ object SyncMessageProcessor {
val address = SignalProtocolAddress(pni.toString(), SignalServiceAddress.DEFAULT_DEVICE_ID) val address = SignalProtocolAddress(pni.toString(), SignalServiceAddress.DEFAULT_DEVICE_ID)
if (AppDependencies.protocolStore.aci().identities().getIdentity(address) != null) { if (AppDependencies.protocolStore.aci().identities().getIdentity(address) != null) {
log(envelope.timestamp!!, "Ignoring identity on sent transcript for $pni because we already have one.") log(envelope.clientTimestamp!!, "Ignoring identity on sent transcript for $pni because we already have one.")
continue continue
} }
try { try {
log(envelope.timestamp!!, "Saving identity from sent transcript for $pni") log(envelope.clientTimestamp!!, "Saving identity from sent transcript for $pni")
val identityKey = IdentityKey(status.destinationPniIdentityKey!!.toByteArray()) val identityKey = IdentityKey(status.destinationPniIdentityKey!!.toByteArray())
AppDependencies.protocolStore.aci().identities().saveIdentity(address, identityKey) AppDependencies.protocolStore.aci().identities().saveIdentity(address, identityKey)
} catch (e: InvalidKeyException) { } catch (e: InvalidKeyException) {
warn(envelope.timestamp!!, "Failed to deserialize identity key for $pni") warn(envelope.clientTimestamp!!, "Failed to deserialize identity key for $pni")
} }
} }
} }
@@ -344,7 +344,7 @@ object SyncMessageProcessor {
val senderRecipientId = senderRecipient.id val senderRecipientId = senderRecipient.id
if (targetMessage == null) { if (targetMessage == null) {
warn(envelope.timestamp!!, "[handleSynchronizeSentEditMessage] Could not find matching message! targetTimestamp: $targetSentTimestamp author: $senderRecipientId") warn(envelope.clientTimestamp!!, "[handleSynchronizeSentEditMessage] Could not find matching message! targetTimestamp: $targetSentTimestamp author: $senderRecipientId")
if (earlyMessageCacheEntry != null) { if (earlyMessageCacheEntry != null) {
AppDependencies.earlyMessageCache.store(senderRecipientId, targetSentTimestamp, earlyMessageCacheEntry) AppDependencies.earlyMessageCache.store(senderRecipientId, targetSentTimestamp, earlyMessageCacheEntry)
PushProcessEarlyMessagesJob.enqueue() PushProcessEarlyMessagesJob.enqueue()
@@ -358,12 +358,12 @@ object SyncMessageProcessor {
} }
if (message.isMediaMessage) { if (message.isMediaMessage) {
handleSynchronizeSentEditMediaMessage(targetMessage, toRecipient, sent, message, envelope.timestamp!!) handleSynchronizeSentEditMediaMessage(targetMessage, toRecipient, sent, message, envelope.clientTimestamp!!)
} else { } else {
handleSynchronizeSentEditTextMessage(targetMessage, toRecipient, sent, message, envelope.timestamp!!) handleSynchronizeSentEditTextMessage(targetMessage, toRecipient, sent, message, envelope.clientTimestamp!!)
} }
} else { } else {
warn(envelope.timestamp!!, "[handleSynchronizeSentEditMessage] Invalid message edit! editTime: ${envelope.serverTimestamp}, targetTime: ${targetMessage.serverTimestamp}, sendAuthor: $senderRecipientId, targetAuthor: ${targetMessage.fromRecipient.id}") warn(envelope.clientTimestamp!!, "[handleSynchronizeSentEditMessage] Invalid message edit! editTime: ${envelope.serverTimestamp}, targetTime: ${targetMessage.serverTimestamp}, sendAuthor: $senderRecipientId, targetAuthor: ${targetMessage.fromRecipient.id}")
} }
} }
@@ -510,12 +510,12 @@ object SyncMessageProcessor {
@Throws(MmsException::class) @Throws(MmsException::class)
private fun handleSynchronizeSentStoryMessage(envelope: Envelope, sent: Sent) { private fun handleSynchronizeSentStoryMessage(envelope: Envelope, sent: Sent) {
log(envelope.timestamp!!, "Synchronize sent story message for " + sent.timestamp) log(envelope.clientTimestamp!!, "Synchronize sent story message for " + sent.timestamp)
val manifest = SentStorySyncManifest.fromRecipientsSet(sent.storyMessageRecipients) val manifest = SentStorySyncManifest.fromRecipientsSet(sent.storyMessageRecipients)
if (sent.isRecipientUpdate == true) { if (sent.isRecipientUpdate == true) {
log(envelope.timestamp!!, "Processing recipient update for story message and exiting...") log(envelope.clientTimestamp!!, "Processing recipient update for story message and exiting...")
SignalDatabase.storySends.applySentStoryManifest(manifest, sent.timestamp!!) SignalDatabase.storySends.applySentStoryManifest(manifest, sent.timestamp!!)
return return
} }
@@ -686,18 +686,18 @@ object SyncMessageProcessor {
@Throws(IOException::class, GroupChangeBusyException::class) @Throws(IOException::class, GroupChangeBusyException::class)
private fun handleSynchronizeSentGv2Update(context: Context, envelope: Envelope, sent: Sent) { private fun handleSynchronizeSentGv2Update(context: Context, envelope: Envelope, sent: Sent) {
log(envelope.timestamp!!, "Synchronize sent GV2 update for message with timestamp " + sent.timestamp!!) log(envelope.clientTimestamp!!, "Synchronize sent GV2 update for message with timestamp " + sent.timestamp!!)
val dataMessage: DataMessage = sent.message!! val dataMessage: DataMessage = sent.message!!
val groupId: GroupId.V2? = dataMessage.groupV2?.groupId val groupId: GroupId.V2? = dataMessage.groupV2?.groupId
if (groupId == null) { if (groupId == null) {
warn(envelope.timestamp!!, "GV2 update missing group id") warn(envelope.clientTimestamp!!, "GV2 update missing group id")
return return
} }
if (MessageContentProcessor.updateGv2GroupFromServerOrP2PChange(context, envelope.timestamp!!, dataMessage.groupV2!!, SignalDatabase.groups.getGroup(groupId)) == null) { if (MessageContentProcessor.updateGv2GroupFromServerOrP2PChange(context, envelope.clientTimestamp!!, dataMessage.groupV2!!, SignalDatabase.groups.getGroup(groupId)) == null) {
log(envelope.timestamp!!, "Ignoring GV2 message for group we are not currently in $groupId") log(envelope.clientTimestamp!!, "Ignoring GV2 message for group we are not currently in $groupId")
} }
} }
@@ -1764,7 +1764,7 @@ object SyncMessageProcessor {
sent: Sent, sent: Sent,
senderRecipient: Recipient senderRecipient: Recipient
): Long { ): Long {
log(envelope.timestamp!!, "Synchronize sent poll creation message.") log(envelope.clientTimestamp!!, "Synchronize sent poll creation message.")
val recipient = getSyncMessageDestination(sent) val recipient = getSyncMessageDestination(sent)
val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient) val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient)
@@ -1795,7 +1795,7 @@ object SyncMessageProcessor {
updateGroupReceiptStatus(sent, messageId, recipient.requireGroupId()) updateGroupReceiptStatus(sent, messageId, recipient.requireGroupId())
} }
log(envelope.timestamp!!, "Inserted sync poll create message as messageId $messageId") log(envelope.clientTimestamp!!, "Inserted sync poll create message as messageId $messageId")
SignalDatabase.messages.markAsSent(messageId, true) SignalDatabase.messages.markAsSent(messageId, true)
@@ -1814,7 +1814,7 @@ object SyncMessageProcessor {
senderRecipient: Recipient, senderRecipient: Recipient,
earlyMessageCacheEntry: EarlyMessageCacheEntry? earlyMessageCacheEntry: EarlyMessageCacheEntry?
): Long { ): Long {
log(envelope.timestamp!!, "Synchronize sent poll terminate message") log(envelope.clientTimestamp!!, "Synchronize sent poll terminate message")
val recipient = getSyncMessageDestination(sent) val recipient = getSyncMessageDestination(sent)
val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient) val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient)
@@ -1827,7 +1827,7 @@ object SyncMessageProcessor {
val pollTerminate = message.pollTerminate!! val pollTerminate = message.pollTerminate!!
val targetMessage = SignalDatabase.messages.getMessageFor(pollTerminate.targetSentTimestamp!!, Recipient.self().id) val targetMessage = SignalDatabase.messages.getMessageFor(pollTerminate.targetSentTimestamp!!, Recipient.self().id)
if (targetMessage == null) { if (targetMessage == null) {
warn(envelope.timestamp!!, "Unable to find target message for poll termination. Putting in early message cache.") warn(envelope.clientTimestamp!!, "Unable to find target message for poll termination. Putting in early message cache.")
if (earlyMessageCacheEntry != null) { if (earlyMessageCacheEntry != null) {
AppDependencies.earlyMessageCache.store(senderRecipient.id, pollTerminate.targetSentTimestamp!!, earlyMessageCacheEntry) AppDependencies.earlyMessageCache.store(senderRecipient.id, pollTerminate.targetSentTimestamp!!, earlyMessageCacheEntry)
PushProcessEarlyMessagesJob.enqueue() PushProcessEarlyMessagesJob.enqueue()
@@ -1836,7 +1836,7 @@ object SyncMessageProcessor {
} }
val poll = SignalDatabase.polls.getPoll(targetMessage.id) val poll = SignalDatabase.polls.getPoll(targetMessage.id)
if (poll == null) { if (poll == null) {
warn(envelope.timestamp!!, "Unable to find poll for poll termination. Dropping.") warn(envelope.clientTimestamp!!, "Unable to find poll for poll termination. Dropping.")
return -1 return -1
} }
@@ -1857,7 +1857,7 @@ object SyncMessageProcessor {
val messageId = SignalDatabase.messages.insertMessageOutbox(outgoingMessage, threadId, false, receiptStatus, null).messageId val messageId = SignalDatabase.messages.insertMessageOutbox(outgoingMessage, threadId, false, receiptStatus, null).messageId
SignalDatabase.messages.markAsSent(messageId, true) SignalDatabase.messages.markAsSent(messageId, true)
log(envelope.timestamp!!, "Inserted sync poll end message as messageId $messageId") log(envelope.clientTimestamp!!, "Inserted sync poll end message as messageId $messageId")
if (expiresInMillis > 0) { if (expiresInMillis > 0) {
SignalDatabase.messages.markExpireStarted(messageId, sent.expirationStartTimestamp ?: 0) SignalDatabase.messages.markExpireStarted(messageId, sent.expirationStartTimestamp ?: 0)
@@ -1874,7 +1874,7 @@ object SyncMessageProcessor {
senderRecipient: Recipient, senderRecipient: Recipient,
earlyMessageCacheEntry: EarlyMessageCacheEntry? earlyMessageCacheEntry: EarlyMessageCacheEntry?
): Long { ): Long {
log(envelope.timestamp!!, "Synchronize pinned message") log(envelope.clientTimestamp!!, "Synchronize pinned message")
val recipient = getSyncMessageDestination(sent) val recipient = getSyncMessageDestination(sent)
val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient) val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient)
@@ -1887,14 +1887,14 @@ object SyncMessageProcessor {
val pinMessage = message.pinMessage!! val pinMessage = message.pinMessage!!
val targetAuthorServiceId: ServiceId = ACI.parseOrThrow(pinMessage.targetAuthorAciBinary!!) val targetAuthorServiceId: ServiceId = ACI.parseOrThrow(pinMessage.targetAuthorAciBinary!!)
if (targetAuthorServiceId.isUnknown) { if (targetAuthorServiceId.isUnknown) {
warn(envelope.timestamp!!, "Unknown author") warn(envelope.clientTimestamp!!, "Unknown author")
return -1 return -1
} }
val targetAuthor = Recipient.externalPush(targetAuthorServiceId) val targetAuthor = Recipient.externalPush(targetAuthorServiceId)
val targetMessage = SignalDatabase.messages.getMessageFor(pinMessage.targetSentTimestamp!!, targetAuthor.id) val targetMessage = SignalDatabase.messages.getMessageFor(pinMessage.targetSentTimestamp!!, targetAuthor.id)
if (targetMessage == null) { if (targetMessage == null) {
warn(envelope.timestamp!!, "Unable to find target message for sync message. Putting in early message cache.") warn(envelope.clientTimestamp!!, "Unable to find target message for sync message. Putting in early message cache.")
if (earlyMessageCacheEntry != null) { if (earlyMessageCacheEntry != null) {
AppDependencies.earlyMessageCache.store(senderRecipient.id, pinMessage.targetSentTimestamp!!, earlyMessageCacheEntry) AppDependencies.earlyMessageCache.store(senderRecipient.id, pinMessage.targetSentTimestamp!!, earlyMessageCacheEntry)
PushProcessEarlyMessagesJob.enqueue() PushProcessEarlyMessagesJob.enqueue()
@@ -1903,12 +1903,12 @@ object SyncMessageProcessor {
} }
if (targetMessage.hasGiftBadge()) { if (targetMessage.hasGiftBadge()) {
warn(envelope.timestamp!!, "Cannot pin gift badge") warn(envelope.clientTimestamp!!, "Cannot pin gift badge")
return -1 return -1
} }
if (targetMessage.isRemoteDelete) { if (targetMessage.isRemoteDelete) {
warn(envelope.timestamp!!, "Cannot pin deleted message") warn(envelope.clientTimestamp!!, "Cannot pin deleted message")
return -1 return -1
} }
@@ -1924,7 +1924,7 @@ object SyncMessageProcessor {
val messageId = SignalDatabase.messages.insertMessageOutbox(outgoingMessage, threadId, false, GroupReceiptTable.STATUS_UNKNOWN, null).messageId val messageId = SignalDatabase.messages.insertMessageOutbox(outgoingMessage, threadId, false, GroupReceiptTable.STATUS_UNKNOWN, null).messageId
SignalDatabase.messages.markAsSent(messageId, true) SignalDatabase.messages.markAsSent(messageId, true)
log(envelope.timestamp!!, "Inserted sync pin message as messageId $messageId") log(envelope.clientTimestamp!!, "Inserted sync pin message as messageId $messageId")
if (expiresInMillis > 0) { if (expiresInMillis > 0) {
SignalDatabase.messages.markExpireStarted(messageId, sent.expirationStartTimestamp ?: 0) SignalDatabase.messages.markExpireStarted(messageId, sent.expirationStartTimestamp ?: 0)

View File

@@ -112,7 +112,6 @@ import org.whispersystems.signalservice.internal.push.OutgoingPushMessage;
import org.whispersystems.signalservice.internal.push.OutgoingPushMessageList; import org.whispersystems.signalservice.internal.push.OutgoingPushMessageList;
import org.whispersystems.signalservice.internal.push.PniSignatureMessage; import org.whispersystems.signalservice.internal.push.PniSignatureMessage;
import org.whispersystems.signalservice.internal.push.Preview; import org.whispersystems.signalservice.internal.push.Preview;
import org.whispersystems.signalservice.internal.push.ProvisioningVersion;
import org.whispersystems.signalservice.internal.push.PushAttachmentData; import org.whispersystems.signalservice.internal.push.PushAttachmentData;
import org.whispersystems.signalservice.internal.push.PushServiceSocket; import org.whispersystems.signalservice.internal.push.PushServiceSocket;
import org.whispersystems.signalservice.internal.push.ReceiptMessage; import org.whispersystems.signalservice.internal.push.ReceiptMessage;
@@ -1602,8 +1601,6 @@ public class SignalServiceMessageSender {
configurationMessage.linkPreviews(configuration.getLinkPreviews().get()); configurationMessage.linkPreviews(configuration.getLinkPreviews().get());
} }
configurationMessage.provisioningVersion(ProvisioningVersion.CURRENT.getValue());
return container.syncMessage(syncMessage.configuration(configurationMessage.build()).build()).build(); return container.syncMessage(syncMessage.configuration(configurationMessage.build()).build()).build();
} }

View File

@@ -104,8 +104,8 @@ public interface EnvelopeContent {
int type; int type;
switch (message.getType()) { switch (message.getType()) {
case CiphertextMessage.PREKEY_TYPE: type = Type.PREKEY_BUNDLE.getValue(); break; case CiphertextMessage.PREKEY_TYPE: type = Type.PREKEY_MESSAGE.getValue(); break;
case CiphertextMessage.WHISPER_TYPE: type = Type.CIPHERTEXT.getValue(); break; case CiphertextMessage.WHISPER_TYPE: type = Type.DOUBLE_RATCHET.getValue(); break;
default: throw new AssertionError("Bad type: " + message.getType()); default: throw new AssertionError("Bad type: " + message.getType());
} }

View File

@@ -187,25 +187,25 @@ public class SignalServiceCipher {
throw new InvalidMessageStructureException("Non-UD envelope is missing a UUID!"); throw new InvalidMessageStructureException("Non-UD envelope is missing a UUID!");
} }
if (envelope.type == Envelope.Type.PREKEY_BUNDLE) { if (envelope.type == Envelope.Type.PREKEY_MESSAGE) {
SignalProtocolAddress sourceAddress = new SignalProtocolAddress(sourceServiceId.toString(), envelope.sourceDevice); SignalProtocolAddress sourceAddress = new SignalProtocolAddress(sourceServiceId.toString(), envelope.sourceDeviceId);
SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress)); SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress));
paddedMessage = sessionCipher.decrypt(new PreKeySignalMessage(envelope.content.toByteArray())); paddedMessage = sessionCipher.decrypt(new PreKeySignalMessage(envelope.content.toByteArray()));
metadata = new SignalServiceMetadata(getSourceAddress(envelope), envelope.sourceDevice, envelope.timestamp, envelope.serverTimestamp, serverDeliveredTimestamp, false, serverGuid, Optional.empty(), destinationStr); metadata = new SignalServiceMetadata(getSourceAddress(envelope), envelope.sourceDeviceId, envelope.clientTimestamp, envelope.serverTimestamp, serverDeliveredTimestamp, false, serverGuid, Optional.empty(), destinationStr);
ciphertextMessageType = CiphertextMessage.PREKEY_TYPE; ciphertextMessageType = CiphertextMessage.PREKEY_TYPE;
signalProtocolStore.clearSenderKeySharedWith(Collections.singleton(sourceAddress)); signalProtocolStore.clearSenderKeySharedWith(Collections.singleton(sourceAddress));
} else if (envelope.type == Envelope.Type.CIPHERTEXT) { } else if (envelope.type == Envelope.Type.DOUBLE_RATCHET) {
SignalProtocolAddress sourceAddress = new SignalProtocolAddress(sourceServiceId.toString(), envelope.sourceDevice); SignalProtocolAddress sourceAddress = new SignalProtocolAddress(sourceServiceId.toString(), envelope.sourceDeviceId);
SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress)); SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress));
paddedMessage = sessionCipher.decrypt(new SignalMessage(envelope.content.toByteArray())); paddedMessage = sessionCipher.decrypt(new SignalMessage(envelope.content.toByteArray()));
metadata = new SignalServiceMetadata(getSourceAddress(envelope), envelope.sourceDevice, envelope.timestamp, envelope.serverTimestamp, serverDeliveredTimestamp, false, serverGuid, Optional.empty(), destinationStr); metadata = new SignalServiceMetadata(getSourceAddress(envelope), envelope.sourceDeviceId, envelope.clientTimestamp, envelope.serverTimestamp, serverDeliveredTimestamp, false, serverGuid, Optional.empty(), destinationStr);
ciphertextMessageType = CiphertextMessage.WHISPER_TYPE; ciphertextMessageType = CiphertextMessage.WHISPER_TYPE;
} else if (envelope.type == Envelope.Type.PLAINTEXT_CONTENT) { } else if (envelope.type == Envelope.Type.PLAINTEXT_CONTENT) {
paddedMessage = new PlaintextContent(envelope.content.toByteArray()).getBody(); paddedMessage = new PlaintextContent(envelope.content.toByteArray()).getBody();
metadata = new SignalServiceMetadata(getSourceAddress(envelope), envelope.sourceDevice, envelope.timestamp, envelope.serverTimestamp, serverDeliveredTimestamp, false, serverGuid, Optional.empty(), destinationStr); metadata = new SignalServiceMetadata(getSourceAddress(envelope), envelope.sourceDeviceId, envelope.clientTimestamp, envelope.serverTimestamp, serverDeliveredTimestamp, false, serverGuid, Optional.empty(), destinationStr);
ciphertextMessageType = CiphertextMessage.PLAINTEXT_CONTENT_TYPE; ciphertextMessageType = CiphertextMessage.PLAINTEXT_CONTENT_TYPE;
} else if (envelope.type == Envelope.Type.UNIDENTIFIED_SENDER) { } else if (envelope.type == Envelope.Type.UNIDENTIFIED_SENDER) {
SignalSealedSessionCipher sealedSessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getServiceId().getRawUuid(), localAddress.getNumber().orElse(null), localDeviceId)); SignalSealedSessionCipher sealedSessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getServiceId().getRawUuid(), localAddress.getNumber().orElse(null), localDeviceId));
@@ -215,7 +215,7 @@ public class SignalServiceCipher {
boolean needsReceipt = true; boolean needsReceipt = true;
if (sourceServiceId != null) { if (sourceServiceId != null) {
Log.w(TAG, "[" + envelope.timestamp + "] Received a UD-encrypted message sent over an identified channel. Marking as needsReceipt=false"); Log.w(TAG, "[" + envelope.clientTimestamp + "] Received a UD-encrypted message sent over an identified channel. Marking as needsReceipt=false");
needsReceipt = false; needsReceipt = false;
} }
@@ -226,7 +226,7 @@ public class SignalServiceCipher {
} }
paddedMessage = result.getPaddedMessage(); paddedMessage = result.getPaddedMessage();
metadata = new SignalServiceMetadata(resultAddress, result.getDeviceId(), envelope.timestamp, envelope.serverTimestamp, serverDeliveredTimestamp, needsReceipt, serverGuid, groupId, destinationStr); metadata = new SignalServiceMetadata(resultAddress, result.getDeviceId(), envelope.clientTimestamp, envelope.serverTimestamp, serverDeliveredTimestamp, needsReceipt, serverGuid, groupId, destinationStr);
} else { } else {
throw new InvalidMetadataMessageException("Unknown type: " + envelope.type); throw new InvalidMetadataMessageException("Unknown type: " + envelope.type);
} }
@@ -236,21 +236,21 @@ public class SignalServiceCipher {
return new Plaintext(metadata, data, ciphertextMessageType); return new Plaintext(metadata, data, ciphertextMessageType);
} catch (DuplicateMessageException e) { } catch (DuplicateMessageException e) {
throw new ProtocolDuplicateMessageException(e, sourceServiceId.toString(), envelope.sourceDevice); throw new ProtocolDuplicateMessageException(e, sourceServiceId.toString(), envelope.sourceDeviceId);
} catch (LegacyMessageException e) { } catch (LegacyMessageException e) {
throw new ProtocolLegacyMessageException(e, sourceServiceId.toString(), envelope.sourceDevice); throw new ProtocolLegacyMessageException(e, sourceServiceId.toString(), envelope.sourceDeviceId);
} catch (InvalidMessageException e) { } catch (InvalidMessageException e) {
throw new ProtocolInvalidMessageException(e, sourceServiceId.toString(), envelope.sourceDevice); throw new ProtocolInvalidMessageException(e, sourceServiceId.toString(), envelope.sourceDeviceId);
} catch (InvalidKeyIdException e) { } catch (InvalidKeyIdException e) {
throw new ProtocolInvalidKeyIdException(e, sourceServiceId.toString(), envelope.sourceDevice); throw new ProtocolInvalidKeyIdException(e, sourceServiceId.toString(), envelope.sourceDeviceId);
} catch (InvalidKeyException e) { } catch (InvalidKeyException e) {
throw new ProtocolInvalidKeyException(e, sourceServiceId.toString(), envelope.sourceDevice); throw new ProtocolInvalidKeyException(e, sourceServiceId.toString(), envelope.sourceDeviceId);
} catch (UntrustedIdentityException e) { } catch (UntrustedIdentityException e) {
throw new ProtocolUntrustedIdentityException(e, sourceServiceId.toString(), envelope.sourceDevice); throw new ProtocolUntrustedIdentityException(e, sourceServiceId.toString(), envelope.sourceDeviceId);
} catch (InvalidVersionException e) { } catch (InvalidVersionException e) {
throw new ProtocolInvalidVersionException(e, sourceServiceId.toString(), envelope.sourceDevice); throw new ProtocolInvalidVersionException(e, sourceServiceId.toString(), envelope.sourceDeviceId);
} catch (NoSessionException e) { } catch (NoSessionException e) {
throw new ProtocolNoSessionException(e, sourceServiceId.toString(), envelope.sourceDevice); throw new ProtocolNoSessionException(e, sourceServiceId.toString(), envelope.sourceDeviceId);
} }
} }

View File

@@ -83,8 +83,8 @@ object EnvelopeContentValidator {
return Result.Invalid("[DataMessage] Missing timestamp!") return Result.Invalid("[DataMessage] Missing timestamp!")
} }
if (dataMessage.timestamp != envelope.timestamp) { if (dataMessage.timestamp != envelope.clientTimestamp) {
return Result.Invalid("[DataMessage] Timestamps don't match! envelope: ${envelope.timestamp}, content: ${dataMessage.timestamp}") return Result.Invalid("[DataMessage] Timestamps don't match! envelope: ${envelope.clientTimestamp}, content: ${dataMessage.timestamp}")
} }
if (dataMessage.quote != null && ACI.parseOrNull(dataMessage.quote.authorAci, dataMessage.quote.authorAciBinary).isNullOrInvalidServiceId()) { if (dataMessage.quote != null && ACI.parseOrNull(dataMessage.quote.authorAci, dataMessage.quote.authorAciBinary).isNullOrInvalidServiceId()) {
@@ -276,8 +276,8 @@ object EnvelopeContentValidator {
private fun validateTypingMessage(envelope: Envelope, typingMessage: TypingMessage): Result { private fun validateTypingMessage(envelope: Envelope, typingMessage: TypingMessage): Result {
return if (typingMessage.timestamp == null) { return if (typingMessage.timestamp == null) {
return Result.Invalid("[TypingMessage] Missing timestamp!") return Result.Invalid("[TypingMessage] Missing timestamp!")
} else if (typingMessage.timestamp != envelope.timestamp) { } else if (typingMessage.timestamp != envelope.clientTimestamp) {
Result.Invalid("[TypingMessage] Timestamps don't match! envelope: ${envelope.timestamp}, content: ${typingMessage.timestamp}") Result.Invalid("[TypingMessage] Timestamps don't match! envelope: ${envelope.clientTimestamp}, content: ${typingMessage.timestamp}")
} else if (typingMessage.action == null) { } else if (typingMessage.action == null) {
Result.Invalid("[TypingMessage] Missing action!") Result.Invalid("[TypingMessage] Missing action!")
} else { } else {

View File

@@ -13,23 +13,79 @@ option java_outer_classname = "SignalServiceProtos";
message Envelope { message Envelope {
enum Type { enum Type {
UNKNOWN = 0; UNKNOWN = 0;
CIPHERTEXT = 1; // content => (version byte | SignalMessage{Content})
/**
* A double-ratchet message represents a "normal," "unsealed-sender" message
* encrypted using the Double Ratchet within an established Signal session.
* Double-ratchet messages include sender information in the plaintext
* portion of the `Envelope`.
*/
DOUBLE_RATCHET = 1; // content => (version byte | SignalMessage{Content})
reserved 2; reserved 2;
reserved "KEY_EXCHANGE"; reserved "KEY_EXCHANGE";
PREKEY_BUNDLE = 3; // content => (version byte | PreKeySignalMessage{Content})
SERVER_DELIVERY_RECEIPT = 5; // legacyMessage => [] AND content => [] /**
UNIDENTIFIED_SENDER = 6; // legacyMessage => [] AND content => ((version byte | UnidentifiedSenderMessage) OR (version byte | Multi-Recipient Sealed Sender Format)) * A prekey message begins a new Signal session. The `content` of a prekey
SENDERKEY_MESSAGE = 7; // legacyMessage => [] AND content => (version byte | SenderKeyMessage) * message is a superset of a double-ratchet message's `content` and
PLAINTEXT_CONTENT = 8; // legacyMessage => [] AND content => (marker byte | Content) * contains the sender's identity public key and information identifying the
* pre-keys used in the message's ciphertext. Like double-ratchet messages,
* prekey messages contain sender information in the plaintext portion of
* the `Envelope`.
*/
PREKEY_MESSAGE = 3; // content => (version byte | PreKeySignalMessage{Content})
/**
* Server delivery receipts are generated by the server when
* "unsealed-sender" messages are delivered to and acknowledged by the
* destination device. Server delivery receipts identify the sender in the
* plaintext portion of the `Envelope` and have no `content`. Note that
* receipts for sealed-sender messages are generated by clients as
* `UNIDENTIFIED_SENDER` messages.
*
* Note that, with server delivery receipts, the "client timestamp" on
* the envelope refers to the timestamp of the original message (i.e. the
* message the server just delivered) and not to the time of delivery. The
* "server timestamp" refers to the time of delivery.
*/
SERVER_DELIVERY_RECEIPT = 5; // content => []
/**
* An unidentified sender message represents a message with no sender
* information in the plaintext portion of the `Envelope`. Unidentified
* sender messages always contain an additional `subtype` in their
* `content`. They may or may not be part of an existing Signal session
* (i.e. an unidentified sender message may have a "prekey message"
* subtype or may indicate an encryption error).
*/
UNIDENTIFIED_SENDER = 6; // content => ((version byte | UnidentifiedSenderMessage) OR (version byte | Multi-Recipient Sealed Sender Format))
reserved 7;
reserved "SENDERKEY_MESSAGE";
/**
* A plaintext message is used solely to convey encryption error receipts
* and never contains encrypted message content. Encryption error receipts
* must be delivered in plaintext because, encryption/decryption of a prior
* message failed and there is no reason to believe that
* encryption/decryption of subsequent messages with the same key material
* would succeed.
*
* Critically, plaintext messages never have "real" message content
* generated by users. Plaintext messages include sender information.
*/
PLAINTEXT_CONTENT = 8; // content => (marker byte | Content)
// next: 9
} }
optional Type type = 1; optional Type type = 1;
reserved 2; // formerly optional string sourceE164 = 2; reserved 2; // formerly optional string sourceE164 = 2;
optional string sourceServiceId = 11; optional string sourceServiceId = 11;
optional uint32 sourceDevice = 7; optional uint32 sourceDeviceId = 7;
optional string destinationServiceId = 13; optional string destinationServiceId = 13;
reserved 3; // formerly optional string relay = 3; reserved 3; // formerly optional string relay = 3;
optional uint64 timestamp = 5; optional uint64 clientTimestamp = 5;
reserved 6; // formerly optional bytes legacyMessage = 6; // Contains an encrypted DataMessage; this field could have been set historically for type 1 or 3 messages; no longer in use reserved 6; // formerly optional bytes legacyMessage = 6; // Contains an encrypted DataMessage; this field could have been set historically for type 1 or 3 messages; no longer in use
optional bytes content = 8; // Contains an encrypted Content optional bytes content = 8; // Contains an encrypted Content
optional string serverGuid = 9; optional string serverGuid = 9;
@@ -48,17 +104,20 @@ message Envelope {
} }
message Content { message Content {
optional DataMessage dataMessage = 1; oneof content {
optional SyncMessage syncMessage = 2; DataMessage dataMessage = 1;
optional CallMessage callMessage = 3; SyncMessage syncMessage = 2;
optional NullMessage nullMessage = 4; CallMessage callMessage = 3;
optional ReceiptMessage receiptMessage = 5; NullMessage nullMessage = 4;
optional TypingMessage typingMessage = 6; ReceiptMessage receiptMessage = 5;
TypingMessage typingMessage = 6;
bytes /* DecryptionErrorMessage */ decryptionErrorMessage = 8;
StoryMessage storyMessage = 9;
EditMessage editMessage = 11;
}
optional bytes /* SenderKeyDistributionMessage */ senderKeyDistributionMessage = 7; optional bytes /* SenderKeyDistributionMessage */ senderKeyDistributionMessage = 7;
optional bytes /* DecryptionErrorMessage */ decryptionErrorMessage = 8;
optional StoryMessage storyMessage = 9;
optional PniSignatureMessage pniSignatureMessage = 10; optional PniSignatureMessage pniSignatureMessage = 10;
optional EditMessage editMessage = 11;
} }
message CallMessage { message CallMessage {
@@ -331,8 +390,8 @@ message DataMessage {
message PollVote { message PollVote {
optional bytes targetAuthorAciBinary = 1; optional bytes targetAuthorAciBinary = 1;
optional uint64 targetSentTimestamp = 2; optional uint64 targetSentTimestamp = 2;
repeated uint32 optionIndexes = 3; // must be in the range [0, options.length) from the PollCreate repeated uint32 optionIndexes = 3;
optional uint32 voteCount = 4; // increment this by 1 each time you vote on a given poll optional uint32 voteCount = 4;
} }
message PinMessage { message PinMessage {
@@ -441,6 +500,12 @@ message TextAttachment {
} }
message Gradient { message Gradient {
// Color ordering:
// 0 degrees: bottom-to-top
// 90 degrees: left-to-right
// 180 degrees: top-to-bottom
// 270 degrees: right-to-left
optional uint32 startColor = 1; // deprecated: this field will be removed in a future release. optional uint32 startColor = 1; // deprecated: this field will be removed in a future release.
optional uint32 endColor = 2; // deprecated: this field will be removed in a future release. optional uint32 endColor = 2; // deprecated: this field will be removed in a future release.
optional uint32 angle = 3; // degrees optional uint32 angle = 3; // degrees
@@ -553,7 +618,7 @@ message SyncMessage {
optional bool unidentifiedDeliveryIndicators = 2; optional bool unidentifiedDeliveryIndicators = 2;
optional bool typingIndicators = 3; optional bool typingIndicators = 3;
reserved /* linkPreviews */ 4; reserved /* linkPreviews */ 4;
optional uint32 provisioningVersion = 5; reserved /* provisioningVersion */ 5;
optional bool linkPreviews = 6; optional bool linkPreviews = 6;
} }
@@ -688,7 +753,7 @@ message SyncMessage {
optional bytes rootKey = 1; optional bytes rootKey = 1;
optional bytes adminPasskey = 2; optional bytes adminPasskey = 2;
optional Type type = 3; // defaults to UPDATE optional Type type = 3; // defaults to UPDATE
reserved 4; // was epoch field, never used reserved /*epoch*/ 4;
} }
message CallLogEvent { message CallLogEvent {
@@ -785,31 +850,40 @@ message SyncMessage {
} }
} }
optional Sent sent = 1; oneof content {
optional Contacts contacts = 2; Sent sent = 1;
Contacts contacts = 2;
Request request = 4;
Blocked blocked = 6;
Verified verified = 7;
Configuration configuration = 9;
ViewOnceOpen viewOnceOpen = 11;
FetchLatest fetchLatest = 12;
Keys keys = 13;
MessageRequestResponse messageRequestResponse = 14;
OutgoingPayment outgoingPayment = 15;
PniChangeNumber pniChangeNumber = 18;
CallEvent callEvent = 19;
CallLinkUpdate callLinkUpdate = 20;
CallLogEvent callLogEvent = 21;
DeleteForMe deleteForMe = 22;
DeviceNameChange deviceNameChange = 23;
AttachmentBackfillRequest attachmentBackfillRequest = 24;
AttachmentBackfillResponse attachmentBackfillResponse = 25;
}
reserved /*groups*/ 3; reserved /*groups*/ 3;
optional Request request = 4;
// Protobufs don't allow `repeated` fields to be inside of `oneof` so while
// the fields below are mutually exclusive with the rest of the values above
// we have to place them outside of `oneof`.
repeated Read read = 5; repeated Read read = 5;
optional Blocked blocked = 6;
optional Verified verified = 7;
optional Configuration configuration = 9;
optional bytes padding = 8;
repeated StickerPackOperation stickerPackOperation = 10; repeated StickerPackOperation stickerPackOperation = 10;
optional ViewOnceOpen viewOnceOpen = 11;
optional FetchLatest fetchLatest = 12;
optional Keys keys = 13;
optional MessageRequestResponse messageRequestResponse = 14;
optional OutgoingPayment outgoingPayment = 15;
repeated Viewed viewed = 16; repeated Viewed viewed = 16;
reserved /*pniIdentity*/ 17; reserved /*pniIdentity*/ 17;
optional PniChangeNumber pniChangeNumber = 18;
optional CallEvent callEvent = 19; optional bytes padding = 8;
optional CallLinkUpdate callLinkUpdate = 20;
optional CallLogEvent callLogEvent = 21;
optional DeleteForMe deleteForMe = 22;
optional DeviceNameChange deviceNameChange = 23;
optional AttachmentBackfillRequest attachmentBackfillRequest = 24;
optional AttachmentBackfillResponse attachmentBackfillResponse = 25;
} }
message AttachmentPointer { message AttachmentPointer {

View File

@@ -16,7 +16,7 @@ import org.whispersystems.signalservice.internal.push.BodyRange
import org.whispersystems.signalservice.internal.push.Content import org.whispersystems.signalservice.internal.push.Content
import org.whispersystems.signalservice.internal.push.DataMessage import org.whispersystems.signalservice.internal.push.DataMessage
import org.whispersystems.signalservice.internal.push.GroupContextV2 import org.whispersystems.signalservice.internal.push.GroupContextV2
import org.whispersystems.signalservice.internal.push.SyncMessage import org.whispersystems.signalservice.internal.push.PniSignatureMessage
class BuildSizeTreeTest { class BuildSizeTreeTest {
@@ -136,12 +136,12 @@ class BuildSizeTreeTest {
fun `multiple top-level fields are all included`() { fun `multiple top-level fields are all included`() {
val msg = Content( val msg = Content(
dataMessage = DataMessage(body = "hi"), dataMessage = DataMessage(body = "hi"),
syncMessage = SyncMessage() pniSignatureMessage = PniSignatureMessage()
) )
val tree = msg.buildSizeTree("Content") val tree = msg.buildSizeTree("Content")
assertThat(tree).contains("dataMessage(") assertThat(tree).contains("dataMessage(")
assertThat(tree).contains("syncMessage(") assertThat(tree).contains("pniSignatureMessage(")
} }
@Test @Test

View File

@@ -23,7 +23,7 @@ class EnvelopeContentValidatorTest {
@Test @Test
fun `validate - ensure mismatched timestamps are marked invalid`() { fun `validate - ensure mismatched timestamps are marked invalid`() {
val envelope = Envelope( val envelope = Envelope(
timestamp = 1234 clientTimestamp = 1234
) )
val content = Content( val content = Content(
@@ -172,11 +172,10 @@ class EnvelopeContentValidatorTest {
fun `validate - plaintext content via envelope type with unexpected DataMessage is invalid`() { fun `validate - plaintext content via envelope type with unexpected DataMessage is invalid`() {
val envelope = Envelope( val envelope = Envelope(
type = Envelope.Type.PLAINTEXT_CONTENT, type = Envelope.Type.PLAINTEXT_CONTENT,
timestamp = 1234 clientTimestamp = 1234
) )
val content = Content( val content = Content(
decryptionErrorMessage = createValidDecryptionErrorMessage(),
dataMessage = DataMessage(timestamp = 1234) dataMessage = DataMessage(timestamp = 1234)
) )
@@ -188,11 +187,10 @@ class EnvelopeContentValidatorTest {
fun `validate - plaintext content via ciphertext message type (sealed sender) with unexpected DataMessage is invalid`() { fun `validate - plaintext content via ciphertext message type (sealed sender) with unexpected DataMessage is invalid`() {
val envelope = Envelope( val envelope = Envelope(
type = Envelope.Type.UNIDENTIFIED_SENDER, type = Envelope.Type.UNIDENTIFIED_SENDER,
timestamp = 1234 clientTimestamp = 1234
) )
val content = Content( val content = Content(
decryptionErrorMessage = createValidDecryptionErrorMessage(),
dataMessage = DataMessage(timestamp = 1234) dataMessage = DataMessage(timestamp = 1234)
) )
@@ -231,7 +229,6 @@ class EnvelopeContentValidatorTest {
) )
val content = Content( val content = Content(
decryptionErrorMessage = createValidDecryptionErrorMessage(),
syncMessage = org.whispersystems.signalservice.internal.push.SyncMessage() syncMessage = org.whispersystems.signalservice.internal.push.SyncMessage()
) )
@@ -242,8 +239,8 @@ class EnvelopeContentValidatorTest {
@Test @Test
fun `validate - regular encrypted message is not subject to plaintext validation`() { fun `validate - regular encrypted message is not subject to plaintext validation`() {
val envelope = Envelope( val envelope = Envelope(
type = Envelope.Type.CIPHERTEXT, type = Envelope.Type.DOUBLE_RATCHET,
timestamp = 1234 clientTimestamp = 1234
) )
val content = Content( val content = Content(

View File

@@ -104,9 +104,9 @@ class SignalClient {
return Envelope( return Envelope(
sourceServiceId = aci.toString(), sourceServiceId = aci.toString(),
sourceDevice = 1, sourceDeviceId = 1,
destinationServiceId = to.aci.toString(), destinationServiceId = to.aci.toString(),
timestamp = sentTimestamp, clientTimestamp = sentTimestamp,
serverTimestamp = sentTimestamp, serverTimestamp = sentTimestamp,
serverGuid = serviceGuid.toString(), serverGuid = serviceGuid.toString(),
type = Envelope.Type.fromValue(outgoingPushMessage.type), type = Envelope.Type.fromValue(outgoingPushMessage.type),
@@ -139,9 +139,9 @@ class SignalClient {
return Envelope( return Envelope(
sourceServiceId = aci.toString(), sourceServiceId = aci.toString(),
sourceDevice = 1, sourceDeviceId = 1,
destinationServiceId = to.aci.toString(), destinationServiceId = to.aci.toString(),
timestamp = sentTimestamp, clientTimestamp = sentTimestamp,
serverTimestamp = sentTimestamp, serverTimestamp = sentTimestamp,
serverGuid = serverGuid.toString(), serverGuid = serverGuid.toString(),
type = Envelope.Type.fromValue(outgoingPushMessage.type), type = Envelope.Type.fromValue(outgoingPushMessage.type),