diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/DataMessageProcessorTest_polls.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/DataMessageProcessorTest_polls.kt index f0dfee0cdc..ecbd58affe 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/DataMessageProcessorTest_polls.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/DataMessageProcessorTest_polls.kt @@ -316,7 +316,7 @@ class DataMessageProcessorTest_polls { private fun insertPoll(allowMultiple: Boolean = true): Long { 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() SignalDatabase.polls.insertPoll("question?", allowMultiple, listOf("a", "b", "c"), alice.id.toLong(), messageId.messageId) return messageId.messageId diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/MessageContentFuzzer.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/MessageContentFuzzer.kt index 92c4f4e207..9b1d281bb0 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/MessageContentFuzzer.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/MessageContentFuzzer.kt @@ -43,7 +43,7 @@ object MessageContentFuzzer { */ fun envelope(timestamp: Long, serverGuid: UUID = UUID.randomUUID()): Envelope { return Envelope.Builder() - .timestamp(timestamp) + .clientTimestamp(timestamp) .serverTimestamp(timestamp + 5) .serverGuidBinary(serverGuid.toByteArray().toByteString()) .build() @@ -292,7 +292,7 @@ object MessageContentFuzzer { body = string() val quoted = quoteAble.random(random) quote = DataMessage.Quote.Builder().buildWith { - id = quoted.envelope.timestamp + id = quoted.envelope.clientTimestamp authorAciBinary = quoted.metadata.sourceServiceId.toByteString() text = quoted.content.dataMessage?.body attachments(quoted.content.dataMessage?.attachments ?: emptyList()) @@ -304,7 +304,7 @@ object MessageContentFuzzer { if (random.nextFloat() < 0.1 && quoteAble.isNotEmpty()) { val quoted = quoteAble.random(random) 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() text = quoted.content.dataMessage?.body } @@ -333,7 +333,7 @@ object MessageContentFuzzer { emoji = emojis.random(random) remove = false targetAuthorAciBinary = reactTo.metadata.sourceServiceId.toByteString() - targetSentTimestamp = reactTo.envelope.timestamp + targetSentTimestamp = reactTo.envelope.clientTimestamp } } } diff --git a/app/src/benchmarkShared/java/org/signal/benchmark/setup/Generator.kt b/app/src/benchmarkShared/java/org/signal/benchmark/setup/Generator.kt index 9de7c9c9aa..75ad7ab7be 100644 --- a/app/src/benchmarkShared/java/org/signal/benchmark/setup/Generator.kt +++ b/app/src/benchmarkShared/java/org/signal/benchmark/setup/Generator.kt @@ -70,8 +70,8 @@ object Generator { val serverGuid = UUID.randomUUID() return Envelope.Builder() .type(Envelope.Type.fromValue(this.type)) - .sourceDevice(1) - .timestamp(timestamp) + .sourceDeviceId(1) + .clientTimestamp(timestamp) .serverTimestamp(timestamp + 1) .destinationServiceId(destination.toString()) .destinationServiceIdBinary(destination.toByteString()) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/migrations/PushProcessMessageJobMigration.kt b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/migrations/PushProcessMessageJobMigration.kt index 1fcd44c487..9505cc0eca 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/migrations/PushProcessMessageJobMigration.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/migrations/PushProcessMessageJobMigration.kt @@ -67,9 +67,9 @@ class PushProcessMessageJobMigration : JobMigration(10) { val envelope = Envelope.Builder() .sourceServiceId(sourceServiceId.toString()) - .sourceDevice(proto.metadata!!.senderDevice) + .sourceDeviceId(proto.metadata!!.senderDevice) .destinationServiceId(destinationServiceId.toString()) - .timestamp(proto.metadata!!.timestamp) + .clientTimestamp(proto.metadata!!.timestamp) .serverGuid(proto.metadata!!.serverGuid) .serverTimestamp(proto.metadata!!.serverReceivedTimestamp) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushProcessMessageJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushProcessMessageJob.kt index 14ddd48126..463d04f5e8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushProcessMessageJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushProcessMessageJob.kt @@ -155,7 +155,7 @@ class PushProcessMessageJob private constructor( try { messageProcessor.process(result.envelope, result.content, result.metadata, result.serverDeliveredTimestamp, localMetric = localReceiveMetric, batchCache = batchCache) } 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 } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/CallMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/CallMessageProcessor.kt index fd935a4025..e4425ed0be 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/CallMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/CallMessageProcessor.kt @@ -41,15 +41,15 @@ object CallMessageProcessor { if (metadata.destinationServiceId is ServiceId.PNI) { 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) ProfileKeySendJob.create(senderRecipient, false)?.let { AppDependencies.jobManager.add(it) } } 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 { - 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 } } @@ -65,12 +65,12 @@ object CallMessageProcessor { } 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) { offer.id!! } else { - warn(envelope.timestamp!!, "Invalid offer, missing id, type, or opaque") + warn(envelope.clientTimestamp!!, "Invalid offer, missing id, type, or opaque") return } @@ -96,12 +96,12 @@ object CallMessageProcessor { answer: CallMessage.Answer, senderRecipientId: RecipientId ) { - log(envelope.timestamp!!, "handleCallAnswerMessage...") + log(envelope.clientTimestamp!!, "handleCallAnswerMessage...") val answerId = if (answer.id != null && answer.opaque != null) { answer.id!! } else { - warn(envelope.timestamp!!, "Invalid answer, missing id or opaque") + warn(envelope.clientTimestamp!!, "Invalid answer, missing id or opaque") return } @@ -122,7 +122,7 @@ object CallMessageProcessor { iceUpdateList: List, senderRecipientId: RecipientId ) { - log(envelope.timestamp!!, "handleCallIceUpdateMessage... " + iceUpdateList.size) + log(envelope.clientTimestamp!!, "handleCallIceUpdateMessage... " + iceUpdateList.size) val iceCandidates: MutableList = ArrayList(iceUpdateList.size) var callId: Long = -1 @@ -142,7 +142,7 @@ object CallMessageProcessor { iceCandidates ) } 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?, senderRecipientId: RecipientId ) { - log(envelope.timestamp!!, "handleCallHangupMessage") + log(envelope.clientTimestamp!!, "handleCallHangupMessage") val (hangupId: Long, hangupDeviceId: Int?) = if (hangup?.id != null) { hangup.id!! to hangup.deviceId } else { - warn(envelope.timestamp!!, "Invalid hangup, null message or missing id/deviceId") + warn(envelope.clientTimestamp!!, "Invalid hangup, null message or missing id/deviceId") return } @@ -170,12 +170,12 @@ object CallMessageProcessor { } 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) { busy.id!! } else { - warn(envelope.timestamp!!, "Invalid busy, missing call id") + warn(envelope.clientTimestamp!!, "Invalid busy, missing call id") return } @@ -184,12 +184,12 @@ object CallMessageProcessor { } 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) { opaque.data_!!.toByteArray() } else { - warn(envelope.timestamp!!, "Invalid opaque message, null data") + warn(envelope.clientTimestamp!!, "Invalid opaque message, null data") return } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/DataMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/DataMessageProcessor.kt index 00afa1617f..678a0bb687 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/DataMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/DataMessageProcessor.kt @@ -149,7 +149,7 @@ object DataMessageProcessor { SignalTrace.beginSection("DataMessageProcessor#gv2PreProcessing") groupProcessResult = MessageContentProcessor.handleGv2PreProcessing( context = context, - timestamp = envelope.timestamp!!, + timestamp = envelope.clientTimestamp!!, content = content, metadata = metadata, groupId = groupId, @@ -171,7 +171,7 @@ object DataMessageProcessor { var messageId: MessageId? = null SignalTrace.beginSection("DataMessageProcessor#messageInsert") 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.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) @@ -197,7 +197,7 @@ object DataMessageProcessor { SignalTrace.beginSection("DataMessageProcessor#postProcess") messageId = messageId ?: insertResult?.messageId?.let { MessageId(it) } if (messageId != null) { - log(envelope.timestamp!!, "Inserted as messageId $messageId") + log(envelope.clientTimestamp!!, "Inserted as messageId $messageId") } if (groupId != null) { @@ -206,12 +206,12 @@ object DataMessageProcessor { else -> SignalDatabase.groups.isUnknownGroup(groupId) } if (unknownGroup) { - handleUnknownGroupMessage(envelope.timestamp!!, message.groupV2!!) + handleUnknownGroupMessage(envelope.clientTimestamp!!, message.groupV2!!) } } 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) { @@ -248,11 +248,11 @@ object DataMessageProcessor { if (insertResult != null && insertResult.threadWasNewlyCreated && !threadRecipient.isGroup && !threadRecipient.isSelf && !senderRecipient.isSystemContact) { val timeSinceLastSync = System.currentTimeMillis() - SignalStore.misc.lastCdsForegroundSyncTime 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)) SignalStore.misc.lastCdsForegroundSyncTime = System.currentTimeMillis() } 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, metadata: EnvelopeMetadata ): InsertResult? { - log(envelope.timestamp!!, "End session message.") + log(envelope.clientTimestamp!!, "End session message.") val incomingMessage = IncomingMessage( from = senderRecipientId, - sentTimeMillis = envelope.timestamp!!, + sentTimeMillis = envelope.clientTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = System.currentTimeMillis(), isUnidentified = metadata.sealedSender, @@ -356,20 +356,20 @@ object DataMessageProcessor { receivedTime: Long, sideEffect: Boolean ): InsertResult? { - log(envelope.timestamp!!, "Expiration update. Side effect: $sideEffect") + log(envelope.clientTimestamp!!, "Expiration update. Side effect: $sideEffect") if (groupId != null) { - warn(envelope.timestamp!!, "Expiration update received for GV2. Ignoring.") + warn(envelope.clientTimestamp!!, "Expiration update received for GV2. Ignoring.") return null } 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 } 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 } @@ -377,7 +377,7 @@ object DataMessageProcessor { val mediaMessage = IncomingMessage( type = MessageType.EXPIRATION_UPDATE, from = senderRecipient.id, - sentTimeMillis = envelope.timestamp!! - if (sideEffect) 1 else 0, + sentTimeMillis = envelope.clientTimestamp!! - if (sideEffect) 1 else 0, serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = receivedTime, expiresIn = expiresIn.inWholeMilliseconds, @@ -419,7 +419,7 @@ object DataMessageProcessor { receivedTime: Long ) { 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) } } @@ -433,13 +433,13 @@ object DataMessageProcessor { senderRecipientId: RecipientId, groupId: GroupId.V2? ): InsertResult? { - log(envelope.timestamp!!, "Story reaction.") + log(envelope.clientTimestamp!!, "Story reaction.") val storyContext = message.storyContext!! val emoji = message.reaction!!.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 } @@ -472,18 +472,18 @@ object DataMessageProcessor { quoteModel = QuoteModel(sentTimestamp, authorRecipientId, displayText, false, story.slideDeck.asAttachments().firstOrNull(), emptyList(), QuoteModel.Type.NORMAL, bodyRanges) expiresIn = message.expireTimerDuration } else { - warn(envelope.timestamp!!, "Story has reactions disabled. Dropping reaction.") + warn(envelope.clientTimestamp!!, "Story has reactions disabled. Dropping reaction.") return null } } 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 } val mediaMessage = IncomingMessage( type = MessageType.STORY_REACTION, from = senderRecipientId, - sentTimeMillis = envelope.timestamp!!, + sentTimeMillis = envelope.clientTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = System.currentTimeMillis(), parentStoryId = parentStoryId, @@ -513,7 +513,7 @@ object DataMessageProcessor { null } } else { - warn(envelope.timestamp!!, "Failed to insert story reaction") + warn(envelope.clientTimestamp!!, "Failed to insert story reaction") null } } catch (e: MmsException) { @@ -533,7 +533,7 @@ object DataMessageProcessor { ): MessageId? { 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 isRemove: Boolean = reaction.remove ?: false @@ -541,19 +541,19 @@ object DataMessageProcessor { val targetSentTimestamp: Long = reaction.targetSentTimestamp!! 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 } 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 } val targetAuthor = Recipient.externalPush(targetAuthorServiceId) val targetMessage = SignalDatabase.messages.getMessageFor(targetSentTimestamp, targetAuthor.id) 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) { AppDependencies.earlyMessageCache.store(targetAuthor.id, targetSentTimestamp, earlyMessageCacheEntry) PushProcessEarlyMessagesJob.enqueue() @@ -562,25 +562,25 @@ object DataMessageProcessor { } 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 } val targetThread = SignalDatabase.threads.getThreadRecord(targetMessage.threadId) 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 } val targetThreadRecipientId = targetThread.recipient.id val groupRecord = SignalDatabase.groups.getGroup(targetThreadRecipientId).orNull() 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 } 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 } @@ -601,7 +601,7 @@ object DataMessageProcessor { fun handleRemoteDelete(context: Context, envelope: Envelope, message: DataMessage, senderRecipientId: RecipientId, earlyMessageCacheEntry: EarlyMessageCacheEntry?): MessageId? { 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 targetMessage: MessageRecord? = SignalDatabase.messages.getMessageFor(targetSentTimestamp, senderRecipientId) @@ -616,7 +616,7 @@ object DataMessageProcessor { MessageId(targetMessage.id) } 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) { AppDependencies.earlyMessageCache.store(senderRecipientId, targetSentTimestamp, earlyMessageCacheEntry) PushProcessEarlyMessagesJob.enqueue() @@ -624,7 +624,7 @@ object DataMessageProcessor { null } 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 } } @@ -644,13 +644,13 @@ object DataMessageProcessor { isActivatePaymentsRequest: Boolean, isPaymentsActivated: Boolean ): InsertResult? { - log(envelope.timestamp!!, "Payment activation request: $isActivatePaymentsRequest activated: $isPaymentsActivated") + log(envelope.clientTimestamp!!, "Payment activation request: $isActivatePaymentsRequest activated: $isPaymentsActivated") Preconditions.checkArgument(isActivatePaymentsRequest || isPaymentsActivated) try { val mediaMessage = IncomingMessage( from = senderRecipientId, - sentTimeMillis = envelope.timestamp!!, + sentTimeMillis = envelope.clientTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = receivedTime, expiresIn = message.expireTimerDuration.inWholeMilliseconds, @@ -675,10 +675,10 @@ object DataMessageProcessor { senderRecipientId: RecipientId, receivedTime: Long ): InsertResult? { - log(envelope.timestamp!!, "Payment message.") + log(envelope.clientTimestamp!!, "Payment message.") 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 } @@ -701,7 +701,7 @@ object DataMessageProcessor { val mediaMessage = IncomingMessage( from = senderRecipientId, body = uuid.toString(), - sentTimeMillis = envelope.timestamp!!, + sentTimeMillis = envelope.clientTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = receivedTime, expiresIn = message.expireTimerDuration.inWholeMilliseconds, @@ -716,9 +716,9 @@ object DataMessageProcessor { return insertResult } } 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) { - warn(envelope.timestamp!!, "Ignoring payment with bad data.", e) + warn(envelope.clientTimestamp!!, "Ignoring payment with bad data.", e) } catch (e: MmsException) { throw StorageFailedException(e, metadata.sourceServiceId.toString(), metadata.sourceDeviceId) } finally { @@ -743,14 +743,14 @@ object DataMessageProcessor { groupId: GroupId.V2?, receivedTime: Long ): InsertResult? { - log(envelope.timestamp!!, "Story reply.") + log(envelope.clientTimestamp!!, "Story reply.") val storyContext: DataMessage.StoryContext = message.storyContext!! val authorServiceId: ServiceId = ACI.parseOrThrow(storyContext.authorAci, storyContext.authorAciBinary) val sentTimestamp: Long = if (storyContext.sentTimestamp != null) { storyContext.sentTimestamp!! } else { - warn(envelope.timestamp!!, "Invalid story reply, missing sentTimestamp") + warn(envelope.clientTimestamp!!, "Invalid story reply, missing sentTimestamp") return null } @@ -798,11 +798,11 @@ object DataMessageProcessor { quoteModel = QuoteModel(sentTimestamp, storyAuthorRecipientId, displayText, false, story.slideDeck.asAttachments().firstOrNull(), emptyList(), QuoteModel.Type.NORMAL, bodyRanges) expiresInMillis = message.expireTimerDuration } else { - warn(envelope.timestamp!!, "Story has replies disabled. Dropping reply.") + warn(envelope.clientTimestamp!!, "Story has replies disabled. Dropping reply.") return null } } 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 } @@ -811,7 +811,7 @@ object DataMessageProcessor { val mediaMessage = IncomingMessage( type = MessageType.NORMAL, from = senderRecipient.id, - sentTimeMillis = envelope.timestamp!!, + sentTimeMillis = envelope.clientTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = System.currentTimeMillis(), parentStoryId = parentStoryId, @@ -843,7 +843,7 @@ object DataMessageProcessor { null } } else { - warn(envelope.timestamp!!, "Failed to insert story reply.") + warn(envelope.clientTimestamp!!, "Failed to insert story reply.") null } } catch (e: MmsException) { @@ -880,7 +880,7 @@ object DataMessageProcessor { val mediaMessage = IncomingMessage( type = MessageType.NORMAL, from = senderRecipient.id, - sentTimeMillis = envelope.timestamp!!, + sentTimeMillis = envelope.clientTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = receivedTime, expiresIn = message.expireTimerDuration.inWholeMilliseconds, @@ -917,7 +917,7 @@ object DataMessageProcessor { localMetrics: SignalLocalMetrics.MessageReceive?, batchCache: BatchCache ): InsertResult? { - log(envelope.timestamp!!, "Media message.") + log(envelope.clientTimestamp!!, "Media message.") notifyTypingStoppedFromIncomingMessage(context, senderRecipient, threadRecipient.id, metadata.sourceDeviceId) @@ -925,11 +925,11 @@ object DataMessageProcessor { SignalDatabase.messages.beginTransaction() try { - val quoteModel: QuoteModel? = getValidatedQuote(context, envelope.timestamp!!, message, senderRecipient, threadRecipient) + val quoteModel: QuoteModel? = getValidatedQuote(context, envelope.clientTimestamp!!, message, senderRecipient, threadRecipient) val contacts: List = getContacts(message) val linkPreviews: List = getLinkPreviews(message.preview, message.body ?: "", false) val mentions: List = 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 = 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 @@ -938,7 +938,7 @@ object DataMessageProcessor { val mediaMessage = IncomingMessage( type = MessageType.NORMAL, from = senderRecipient.id, - sentTimeMillis = envelope.timestamp!!, + sentTimeMillis = envelope.clientTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = receivedTime, expiresIn = message.expireTimerDuration.inWholeMilliseconds, @@ -1018,7 +1018,7 @@ object DataMessageProcessor { localMetrics: SignalLocalMetrics.MessageReceive?, batchCache: BatchCache ): InsertResult? { - log(envelope.timestamp!!, "Text message.") + log(envelope.clientTimestamp!!, "Text message.") val body = message.body ?: "" @@ -1029,7 +1029,7 @@ object DataMessageProcessor { val textMessage = IncomingMessage( type = MessageType.NORMAL, from = senderRecipient.id, - sentTimeMillis = envelope.timestamp!!, + sentTimeMillis = envelope.clientTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = receivedTime, body = body, @@ -1058,15 +1058,15 @@ object DataMessageProcessor { senderRecipientId: RecipientId, groupId: GroupId.V2? ) { - log(envelope.timestamp!!, "Group call update message.") + log(envelope.clientTimestamp!!, "Group call update message.") if (groupId == null) { - warn(envelope.timestamp!!, "Invalid group for group call update message") + warn(envelope.clientTimestamp!!, "Invalid group for group call update message") return } 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 } @@ -1091,7 +1091,7 @@ object DataMessageProcessor { groupId: GroupId.V2?, receivedTime: Long ): InsertResult? { - log(envelope.timestamp!!, "Handle poll creation") + log(envelope.clientTimestamp!!, "Handle poll creation") val poll: DataMessage.PollCreate = message.pollCreate!! handlePossibleExpirationUpdate(envelope, metadata, senderRecipient, threadRecipient, groupId, message.expireTimerDuration, message.expireTimerVersion, receivedTime) @@ -1099,28 +1099,28 @@ object DataMessageProcessor { if (groupId != null) { val groupRecord = SignalDatabase.groups.getGroup(groupId).orNull() 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 } } 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 } 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 } 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 } val pollMessage = IncomingMessage( type = MessageType.NORMAL, from = senderRecipient.id, - sentTimeMillis = envelope.timestamp!!, + sentTimeMillis = envelope.clientTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = receivedTime, groupId = groupId, @@ -1159,7 +1159,7 @@ object DataMessageProcessor { val pollTerminate: DataMessage.PollTerminate = message.pollTerminate!! 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) @@ -1170,14 +1170,14 @@ object DataMessageProcessor { val poll = SignalDatabase.polls.getPoll(messageId.id) 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 } val pollMessage = IncomingMessage( type = MessageType.POLL_TERMINATE, from = senderRecipient.id, - sentTimeMillis = envelope.timestamp!!, + sentTimeMillis = envelope.clientTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = receivedTime, groupId = groupId, @@ -1207,11 +1207,11 @@ object DataMessageProcessor { val pollVote: DataMessage.PollVote = message.pollVote!! 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!!) 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 } @@ -1223,30 +1223,30 @@ object DataMessageProcessor { val targetMessage = SignalDatabase.messages.getMessageRecord(messageId.id) val pollId = SignalDatabase.polls.getPollId(messageId.id) 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 } val existingVoteCount = SignalDatabase.polls.getCurrentPollVoteCount(pollId, senderRecipient.id.toLong()) val currentVoteCount = pollVote.voteCount?.toLong() ?: 0 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 } val allOptionIds = SignalDatabase.polls.getPollOptionIds(pollId) 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 } 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 } 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 } @@ -1274,13 +1274,13 @@ object DataMessageProcessor { earlyMessageCacheEntry: EarlyMessageCacheEntry? = null ): InsertResult? { 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) val targetAuthorServiceId: ServiceId = ACI.parseOrThrow(pinMessage.targetAuthorAciBinary!!) 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 } @@ -1288,7 +1288,7 @@ object DataMessageProcessor { val targetMessage: MmsMessageRecord? = SignalDatabase.messages.getMessageFor(pinMessage.targetSentTimestamp!!, targetAuthor.id) as? MmsMessageRecord 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) { AppDependencies.earlyMessageCache.store(targetAuthor.id, pinMessage.targetSentTimestamp!!, earlyMessageCacheEntry) PushProcessEarlyMessagesJob.enqueue() @@ -1297,38 +1297,38 @@ object DataMessageProcessor { } 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 } if (targetMessage.hasGiftBadge()) { - warn(envelope.timestamp!!, "[handlePinMessage] Cannot pin a gift badge") + warn(envelope.clientTimestamp!!, "[handlePinMessage] Cannot pin a gift badge") return null } val targetThread = SignalDatabase.threads.getThreadRecord(targetMessage.threadId) 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 } 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 } val groupRecord = SignalDatabase.groups.getGroup(threadRecipient.id).orNull() 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 } 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 } 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 } @@ -1337,7 +1337,7 @@ object DataMessageProcessor { val pinnedMessage = IncomingMessage( type = MessageType.PINNED_MESSAGE, from = senderRecipient.id, - sentTimeMillis = envelope.timestamp!!, + sentTimeMillis = envelope.clientTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = receivedTime, expiresIn = message.expireTimerDuration.inWholeMilliseconds, @@ -1350,7 +1350,7 @@ object DataMessageProcessor { val insertResult: InsertResult? = SignalDatabase.messages.insertMessageInbox(pinnedMessage).orNull() 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) { AppDependencies.pinnedMessageManager.scheduleIfNecessary() } @@ -1368,11 +1368,11 @@ object DataMessageProcessor { earlyMessageCacheEntry: EarlyMessageCacheEntry? = null ): MessageId? { 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!!) 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 } @@ -1380,7 +1380,7 @@ object DataMessageProcessor { val targetMessage: MmsMessageRecord? = SignalDatabase.messages.getMessageFor(unpinMessage.targetSentTimestamp!!, targetAuthor.id) as? MmsMessageRecord 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) { AppDependencies.earlyMessageCache.store(targetAuthor.id, unpinMessage.targetSentTimestamp!!, earlyMessageCacheEntry) PushProcessEarlyMessagesJob.enqueue() @@ -1389,38 +1389,38 @@ object DataMessageProcessor { } 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 } if (targetMessage.hasGiftBadge()) { - warn(envelope.timestamp!!, "[handleUnpinMessage] Cannot pin a gift badge") + warn(envelope.clientTimestamp!!, "[handleUnpinMessage] Cannot pin a gift badge") return null } val targetThread = SignalDatabase.threads.getThreadRecord(targetMessage.threadId) 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 } 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 } val groupRecord = SignalDatabase.groups.getGroup(threadRecipient.id).orNull() 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 } 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 } 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 } @@ -1432,25 +1432,25 @@ object DataMessageProcessor { fun handleAdminRemoteDelete(context: Context, envelope: Envelope, message: DataMessage, senderRecipient: Recipient, threadRecipient: Recipient, earlyMessageCacheEntry: EarlyMessageCacheEntry?): MessageId? { 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 } 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 targetAuthorServiceId: ServiceId = ACI.parseOrThrow(delete.targetAuthorAciBinary!!) if (targetAuthorServiceId.isUnknown) { - warn(envelope.timestamp!!, "[handleAdminRemoteDelete] Invalid author.") + warn(envelope.clientTimestamp!!, "[handleAdminRemoteDelete] Invalid author.") return null } val targetAuthor = Recipient.externalPush(targetAuthorServiceId) val targetMessage: MessageRecord? = SignalDatabase.messages.getMessageFor(targetSentTimestamp, targetAuthor.id) 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) { AppDependencies.earlyMessageCache.store(targetAuthor.id, targetSentTimestamp, earlyMessageCacheEntry) PushProcessEarlyMessagesJob.enqueue() @@ -1460,19 +1460,19 @@ object DataMessageProcessor { val targetThread = SignalDatabase.threads.getThreadRecord(targetMessage.threadId) 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 } val targetThreadRecipientId = targetThread.recipient.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 } val groupRecord = SignalDatabase.groups.getGroup(targetThreadRecipientId).orNull() if (groupRecord == null || !groupRecord.isV2Group) { - warn(envelope.timestamp!!, "[handleAdminRemoteDelete] Invalid group.") + warn(envelope.clientTimestamp!!, "[handleAdminRemoteDelete] Invalid group.") return null } @@ -1481,7 +1481,7 @@ object DataMessageProcessor { AppDependencies.messageNotifier.updateNotification(context, ConversationId.fromMessageRecord(targetMessage)) MessageId(targetMessage.id) } 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 } } @@ -1627,7 +1627,7 @@ object DataMessageProcessor { ): MessageId? { val targetMessage = SignalDatabase.messages.getMessageFor(targetSentTimestamp, targetAuthor.id) 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) { AppDependencies.earlyMessageCache.store(senderRecipient.id, targetSentTimestamp, earlyMessageCacheEntry) PushProcessEarlyMessagesJob.enqueue() @@ -1636,22 +1636,22 @@ object DataMessageProcessor { } 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 } val targetThread = SignalDatabase.threads.getThreadRecord(targetMessage.threadId) 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 } val groupRecord = SignalDatabase.groups.getGroup(targetThread.recipient.id).orNull() 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 } 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 } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/EditMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/EditMessageProcessor.kt index 1f0ca1d1fa..5d798a429c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/EditMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/EditMessageProcessor.kt @@ -50,13 +50,13 @@ object EditMessageProcessor { ) { 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 val targetThreadRecipient: Recipient? = if (targetMessage != null) SignalDatabase.threads.getRecipientForThreadId(targetMessage.threadId) else 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) { AppDependencies.earlyMessageCache.store(senderRecipient.id, editMessage.targetSentTimestamp!!, earlyMessageCacheEntry) @@ -78,12 +78,12 @@ object EditMessageProcessor { val validTarget = !originalMessage.isViewOnce && !originalMessage.hasAudio() && !originalMessage.hasSharedContact() 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 } - if (groupId != null && MessageContentProcessor.handleGv2PreProcessing(context, envelope.timestamp!!, content, metadata, groupId, message.groupV2!!, senderRecipient) == MessageContentProcessor.Gv2PreProcessResult.IGNORE) { - warn(envelope.timestamp!!, "[handleEditMessage] Group processor indicated we should ignore this.") + if (groupId != null && MessageContentProcessor.handleGv2PreProcessing(context, envelope.clientTimestamp!!, content, metadata, groupId, message.groupV2!!, senderRecipient) == MessageContentProcessor.Gv2PreProcessResult.IGNORE) { + warn(envelope.clientTimestamp!!, "[handleEditMessage] Group processor indicated we should ignore this.") return } @@ -187,8 +187,8 @@ object EditMessageProcessor { val textMessage = IncomingMessage( type = MessageType.NORMAL, from = senderRecipientId, - sentTimeMillis = envelope.timestamp!!, - serverTimeMillis = envelope.timestamp!!, + sentTimeMillis = envelope.clientTimestamp!!, + serverTimeMillis = envelope.clientTimestamp!!, receivedTimeMillis = targetMessage.dateReceived, body = message.body, groupId = groupId, diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.kt index dbebf6e386..cbe5c5d8db 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.kt @@ -291,8 +291,8 @@ class IncomingMessageObserver( null } - Envelope.Type.PREKEY_BUNDLE, - Envelope.Type.CIPHERTEXT, + Envelope.Type.PREKEY_MESSAGE, + Envelope.Type.DOUBLE_RATCHET, Envelope.Type.UNIDENTIFIED_SENDER, Envelope.Type.PLAINTEXT_CONTENT -> { SignalTrace.beginSection("IncomingMessageObserver#processMessage") @@ -343,7 +343,7 @@ class IncomingMessageObserver( jobs += PushProcessMessageErrorJob( result.toMessageState(), result.errorMetadata.toExceptionMetadata(), - result.envelope.timestamp!! + result.envelope.clientTimestamp!! ) AppDependencies.jobManager.startChain(jobs) @@ -369,9 +369,9 @@ class IncomingMessageObserver( val senderId = RecipientId.from(serviceId) - Log.i(TAG, "Received server receipt. Sender: $senderId, Device: ${envelope.sourceDevice}, Timestamp: ${envelope.timestamp}") - SignalDatabase.messages.incrementDeliveryReceiptCount(envelope.timestamp!!, senderId, System.currentTimeMillis()) - SignalDatabase.messageLog.deleteEntryForRecipient(envelope.timestamp!!, senderId, envelope.sourceDevice!!) + Log.i(TAG, "Received server receipt. Sender: $senderId, Device: ${envelope.sourceDeviceId}, Timestamp: ${envelope.clientTimestamp}") + SignalDatabase.messages.incrementDeliveryReceiptCount(envelope.clientTimestamp!!, senderId, System.currentTimeMillis()) + SignalDatabase.messageLog.deleteEntryForRecipient(envelope.clientTimestamp!!, senderId, envelope.sourceDeviceId!!) } private fun MessageDecryptor.Result.toMessageState(): MessageState { diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.kt index fe3c50b637..51c57e6917 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.kt @@ -350,11 +350,11 @@ open class MessageContentProcessor(private val context: Context) { val earlyCacheEntries: List? = AppDependencies .earlyMessageCache - .retrieve(senderRecipient.id, envelope.timestamp!!) + .retrieve(senderRecipient.id, envelope.clientTimestamp!!) .orNull() 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) { 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) if (shouldIgnore(content, senderRecipient, threadRecipient)) { - log(envelope.timestamp!!, "Ignoring message.") + log(envelope.clientTimestamp!!, "Ignoring message.") return } - val pending: PendingRetryReceiptModel? = AppDependencies.pendingRetryReceiptCache.get(senderRecipient.id, envelope.timestamp!!) - val receivedTime: Long = handlePendingRetry(pending, envelope.timestamp!!, threadRecipient) + val pending: PendingRetryReceiptModel? = AppDependencies.pendingRetryReceiptCache.get(senderRecipient.id, envelope.clientTimestamp!!) + 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() when { content.dataMessage != null -> { @@ -482,12 +482,12 @@ open class MessageContentProcessor(private val context: Context) { } content.callMessage != null -> { - log(envelope.timestamp!!, "Got call message...") + log(envelope.clientTimestamp!!, "Got call message...") val message: CallMessage = content.callMessage!! 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 } @@ -541,12 +541,12 @@ open class MessageContentProcessor(private val context: Context) { } else -> { - warn(envelope.timestamp!!, "Got unrecognized message!") + warn(envelope.clientTimestamp!!, "Got unrecognized message!") } } if (pending != null) { - warn(envelope.timestamp!!, "Pending retry was processed. Deleting.") + warn(envelope.clientTimestamp!!, "Pending retry was processed. Deleting.") AppDependencies.pendingRetryReceiptCache.delete(pending) } } @@ -565,7 +565,7 @@ open class MessageContentProcessor(private val context: Context) { val threadId: Long = if (typingMessage.groupId != null) { val groupId = GroupId.push(typingMessage.groupId!!) 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 } @@ -576,7 +576,7 @@ open class MessageContentProcessor(private val context: Context) { } 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 } @@ -591,19 +591,19 @@ open class MessageContentProcessor(private val context: Context) { private fun handleRetryReceipt(envelope: Envelope, metadata: EnvelopeMetadata, decryptionErrorMessage: DecryptionErrorMessage, senderRecipient: Recipient) { if (!RemoteConfig.retryReceipts) { - warn(envelope.timestamp!!, "[RetryReceipt] Feature flag disabled, skipping retry receipt.") + warn(envelope.clientTimestamp!!, "[RetryReceipt] Feature flag disabled, skipping retry receipt.") return } 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 } 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) { - 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 } @@ -626,18 +626,18 @@ open class MessageContentProcessor(private val context: Context) { val relatedMessage = findRetryReceiptRelatedMessage(messageLogEntry, sentTimestamp) 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 } val threadRecipient = SignalDatabase.threads.getRecipientForThreadId(relatedMessage.threadId) 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 } 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 } @@ -661,7 +661,7 @@ open class MessageContentProcessor(private val context: Context) { SignalDatabase.senderKeyShared.delete(distributionId, setOf(requesterAddress)) 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( ResendMessageJob( messageLogEntry.recipientId, @@ -674,7 +674,7 @@ open class MessageContentProcessor(private val context: Context) { ) ) } 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)) } } @@ -683,24 +683,24 @@ open class MessageContentProcessor(private val context: Context) { var archivedSession = false 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 } if (decryptionErrorMessage.ratchetKey.isPresent) { 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) archivedSession = true } 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 { - 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) { - 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( ResendMessageJob( messageLogEntry.recipientId, @@ -713,10 +713,10 @@ open class MessageContentProcessor(private val context: Context) { ) ) } 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)) } 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.") } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageDecryptor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageDecryptor.kt index abec4b15db..56bdfef079 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageDecryptor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageDecryptor.kt @@ -142,7 +142,7 @@ object MessageDecryptor { val followUpOperations: MutableList = 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.") followUpOperations += FollowUpOperation { PreKeysSyncJob.create().asChain() @@ -164,7 +164,7 @@ object MessageDecryptor { envelope.newBuilder() .sourceServiceId(if (BuildConfig.USE_STRING_ID) cipherResult.metadata.sourceServiceId.toString() else null) .sourceServiceIdBinary(if (RemoteConfig.useBinaryId) cipherResult.metadata.sourceServiceId.toByteString() else null) - .sourceDevice(cipherResult.metadata.sourceDeviceId) + .sourceDeviceId(cipherResult.metadata.sourceDeviceId) .build() } else { envelope @@ -255,7 +255,7 @@ object MessageDecryptor { followUpOperations += FollowUpOperation { 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!") } @@ -276,7 +276,7 @@ object MessageDecryptor { } 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()) } @@ -320,7 +320,7 @@ object MessageDecryptor { Log.w(TAG, "${logPrefix(envelope)} Decryption error for a sync message! Enqueuing a session reset job.", true) followUpOperations += FollowUpOperation { - AutomaticSessionResetJob(sender.id, senderDevice, envelope.timestamp!!).asChain() + AutomaticSessionResetJob(sender.id, senderDevice, envelope.clientTimestamp!!).asChain() } 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 // 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) PreKeysSyncJob.create(forceRotationRequested = true).asChain().then(retryJob) } else { @@ -392,7 +392,7 @@ object MessageDecryptor { 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() null } @@ -491,26 +491,26 @@ object MessageDecryptor { } private fun logPrefix(envelope: Envelope): String { - return logPrefix(envelope.timestamp!!, ServiceId.parseOrNull(envelope.sourceServiceId, envelope.sourceServiceIdBinary)?.logString() ?: "", envelope.sourceDevice) + return logPrefix(envelope.clientTimestamp!!, ServiceId.parseOrNull(envelope.sourceServiceId, envelope.sourceServiceIdBinary)?.logString() ?: "", envelope.sourceDeviceId) } 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 { - 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 { - 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 { 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 { - 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() } - 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) return SendRetryReceiptJob(sender.id, Optional.ofNullable(groupId), decryptionErrorMessage) } @@ -541,7 +541,7 @@ object MessageDecryptor { try { GroupId.push(this.groupId.get()) } catch (e: BadGroupIdException) { - Log.w(TAG, "[${envelope.timestamp}] Bad groupId!", true) + Log.w(TAG, "[${envelope.clientTimestamp}] Bad groupId!", true) null } } else { @@ -551,8 +551,8 @@ object MessageDecryptor { private fun Int.toCiphertextMessageType(): Int { return when (this) { - Envelope.Type.CIPHERTEXT.value -> CiphertextMessage.WHISPER_TYPE - Envelope.Type.PREKEY_BUNDLE.value -> CiphertextMessage.PREKEY_TYPE + Envelope.Type.DOUBLE_RATCHET.value -> CiphertextMessage.WHISPER_TYPE + Envelope.Type.PREKEY_MESSAGE.value -> CiphertextMessage.PREKEY_TYPE Envelope.Type.UNIDENTIFIED_SENDER.value -> CiphertextMessage.SENDERKEY_TYPE Envelope.Type.PLAINTEXT_CONTENT.value -> CiphertextMessage.PLAINTEXT_CONTENT_TYPE else -> CiphertextMessage.WHISPER_TYPE diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/ReceiptMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/ReceiptMessageProcessor.kt index 664dc38d45..97c20ea784 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/ReceiptMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/ReceiptMessageProcessor.kt @@ -31,7 +31,7 @@ object ReceiptMessageProcessor { ReceiptMessage.Type.DELIVERY -> handleDeliveryReceipt(envelope, metadata, receiptMessage, senderRecipient.id, batchCache) ReceiptMessage.Type.READ -> handleReadReceipt(context, senderRecipient.id, envelope, metadata, receiptMessage, earlyMessageCacheEntry, batchCache) 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, 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 SignalTrace.beginSection("ReceiptMessageProcessor#incrementDeliveryReceiptCounts") - val missingTargetTimestamps: Set = SignalDatabase.messages.incrementDeliveryReceiptCounts(deliveryReceipt.timestamp, senderRecipientId, envelope.timestamp!!, stopwatch, batchCache.deliveryReceiptLookupCache) + val missingTargetTimestamps: Set = SignalDatabase.messages.incrementDeliveryReceiptCounts(deliveryReceipt.timestamp, senderRecipientId, envelope.clientTimestamp!!, stopwatch, batchCache.deliveryReceiptLookupCache) SignalTrace.endSection() 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 } @@ -79,21 +79,21 @@ object ReceiptMessageProcessor { batchCache: BatchCache ) { 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 } - 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") - val missingTargetTimestamps: Set = SignalDatabase.messages.incrementReadReceiptCounts(readReceipt.timestamp, senderRecipientId, envelope.timestamp!!, batchCache.readReceiptLookupCache) + val missingTargetTimestamps: Set = SignalDatabase.messages.incrementReadReceiptCounts(readReceipt.timestamp, senderRecipientId, envelope.clientTimestamp!!, batchCache.readReceiptLookupCache) SignalTrace.endSection() if (missingTargetTimestamps.isNotEmpty()) { val selfId = Recipient.self().id 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) { AppDependencies.earlyMessageCache.store(selfId, targetTimestamp, earlyMessageCacheEntry) } @@ -117,18 +117,18 @@ object ReceiptMessageProcessor { val storyViewedReceipts = SignalStore.story.viewedReceiptsEnabled 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 } - 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 = if (readReceipts && storyViewedReceipts) { - SignalDatabase.messages.incrementViewedReceiptCounts(viewedReceipt.timestamp, senderRecipientId, envelope.timestamp!!) + SignalDatabase.messages.incrementViewedReceiptCounts(viewedReceipt.timestamp, senderRecipientId, envelope.clientTimestamp!!) } else if (readReceipts) { - SignalDatabase.messages.incrementViewedNonStoryReceiptCounts(viewedReceipt.timestamp, senderRecipientId, envelope.timestamp!!) + SignalDatabase.messages.incrementViewedNonStoryReceiptCounts(viewedReceipt.timestamp, senderRecipientId, envelope.clientTimestamp!!) } else { - SignalDatabase.messages.incrementViewedStoryReceiptCounts(viewedReceipt.timestamp, senderRecipientId, envelope.timestamp!!) + SignalDatabase.messages.incrementViewedStoryReceiptCounts(viewedReceipt.timestamp, senderRecipientId, envelope.clientTimestamp!!) } val foundTargetTimestamps: Set = viewedReceipt.timestamp.toSet() - missingTargetTimestamps.toSet() @@ -138,7 +138,7 @@ object ReceiptMessageProcessor { val selfId = Recipient.self().id 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) { AppDependencies.earlyMessageCache.store(selfId, targetTimestamp, earlyMessageCacheEntry) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/StoryMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/StoryMessageProcessor.kt index f196472041..e2fdc86826 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/StoryMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/StoryMessageProcessor.kt @@ -33,20 +33,20 @@ object StoryMessageProcessor { fun process(envelope: Envelope, content: Content, metadata: EnvelopeMetadata, senderRecipient: Recipient, threadRecipient: Recipient) { val storyMessage = content.storyMessage!! - log(envelope.timestamp!!, "Story message.") + log(envelope.clientTimestamp!!, "Story message.") 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 } 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 } 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 } @@ -64,7 +64,7 @@ object StoryMessageProcessor { val mediaMessage = IncomingMessage( type = MessageType.NORMAL, from = senderRecipient.id, - sentTimeMillis = envelope.timestamp!!, + sentTimeMillis = envelope.clientTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = System.currentTimeMillis(), storyType = storyType, diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt index 84db9187d5..65974f498d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt @@ -162,26 +162,26 @@ object SyncMessageProcessor { when { syncMessage.sent != null -> handleSynchronizeSentMessage(context, envelope, content, metadata, syncMessage.sent!!, senderRecipient, threadRecipient, earlyMessageCacheEntry) - syncMessage.request != null -> handleSynchronizeRequestMessage(context, syncMessage.request!!, envelope.timestamp!!) - syncMessage.read.isNotEmpty() -> handleSynchronizeReadMessage(context, syncMessage.read, envelope.timestamp!!, earlyMessageCacheEntry) - syncMessage.viewed.isNotEmpty() -> handleSynchronizeViewedMessage(context, syncMessage.viewed, envelope.timestamp!!) - syncMessage.viewOnceOpen != null -> handleSynchronizeViewOnceOpenMessage(context, syncMessage.viewOnceOpen!!, envelope.timestamp!!, earlyMessageCacheEntry) + syncMessage.request != null -> handleSynchronizeRequestMessage(context, syncMessage.request!!, envelope.clientTimestamp!!) + syncMessage.read.isNotEmpty() -> handleSynchronizeReadMessage(context, syncMessage.read, envelope.clientTimestamp!!, earlyMessageCacheEntry) + syncMessage.viewed.isNotEmpty() -> handleSynchronizeViewedMessage(context, syncMessage.viewed, envelope.clientTimestamp!!) + syncMessage.viewOnceOpen != null -> handleSynchronizeViewOnceOpenMessage(context, syncMessage.viewOnceOpen!!, envelope.clientTimestamp!!, earlyMessageCacheEntry) syncMessage.verified != null -> handleSynchronizeVerifiedMessage(context, syncMessage.verified!!) - syncMessage.stickerPackOperation.isNotEmpty() -> handleSynchronizeStickerPackOperation(syncMessage.stickerPackOperation, envelope.timestamp!!) - syncMessage.configuration != null -> handleSynchronizeConfigurationMessage(context, syncMessage.configuration!!, envelope.timestamp!!) - syncMessage.blocked != null -> handleSynchronizeBlockedListMessage(syncMessage.blocked!!, envelope.timestamp!!) - syncMessage.fetchLatest?.type != null -> handleSynchronizeFetchMessage(syncMessage.fetchLatest!!.type!!, envelope.timestamp!!) - syncMessage.messageRequestResponse != null -> handleSynchronizeMessageRequestResponse(syncMessage.messageRequestResponse!!, envelope.timestamp!!) - syncMessage.outgoingPayment != null -> handleSynchronizeOutgoingPayment(syncMessage.outgoingPayment!!, envelope.timestamp!!) - syncMessage.contacts != null -> handleSynchronizeContacts(syncMessage.contacts!!, envelope.timestamp!!) - syncMessage.keys != null -> handleSynchronizeKeys(syncMessage.keys!!, envelope.timestamp!!) - syncMessage.callEvent != null -> handleSynchronizeCallEvent(syncMessage.callEvent!!, envelope.timestamp!!) - syncMessage.callLinkUpdate != null -> handleSynchronizeCallLink(syncMessage.callLinkUpdate!!, envelope.timestamp!!) - syncMessage.callLogEvent != null -> handleSynchronizeCallLogEvent(syncMessage.callLogEvent!!, envelope.timestamp!!) - syncMessage.deleteForMe != null -> handleSynchronizeDeleteForMe(context, syncMessage.deleteForMe!!, envelope.timestamp!!, earlyMessageCacheEntry) - syncMessage.attachmentBackfillRequest != null -> handleSynchronizeAttachmentBackfillRequest(syncMessage.attachmentBackfillRequest!!, envelope.timestamp!!) - syncMessage.attachmentBackfillResponse != null -> warn(envelope.timestamp!!, "Contains a backfill response, but we don't handle these!") - else -> warn(envelope.timestamp!!, "Contains no known sync types...") + syncMessage.stickerPackOperation.isNotEmpty() -> handleSynchronizeStickerPackOperation(syncMessage.stickerPackOperation, envelope.clientTimestamp!!) + syncMessage.configuration != null -> handleSynchronizeConfigurationMessage(context, syncMessage.configuration!!, envelope.clientTimestamp!!) + syncMessage.blocked != null -> handleSynchronizeBlockedListMessage(syncMessage.blocked!!, envelope.clientTimestamp!!) + syncMessage.fetchLatest?.type != null -> handleSynchronizeFetchMessage(syncMessage.fetchLatest!!.type!!, envelope.clientTimestamp!!) + syncMessage.messageRequestResponse != null -> handleSynchronizeMessageRequestResponse(syncMessage.messageRequestResponse!!, envelope.clientTimestamp!!) + syncMessage.outgoingPayment != null -> handleSynchronizeOutgoingPayment(syncMessage.outgoingPayment!!, envelope.clientTimestamp!!) + syncMessage.contacts != null -> handleSynchronizeContacts(syncMessage.contacts!!, envelope.clientTimestamp!!) + syncMessage.keys != null -> handleSynchronizeKeys(syncMessage.keys!!, envelope.clientTimestamp!!) + syncMessage.callEvent != null -> handleSynchronizeCallEvent(syncMessage.callEvent!!, envelope.clientTimestamp!!) + syncMessage.callLinkUpdate != null -> handleSynchronizeCallLink(syncMessage.callLinkUpdate!!, envelope.clientTimestamp!!) + syncMessage.callLogEvent != null -> handleSynchronizeCallLogEvent(syncMessage.callLogEvent!!, envelope.clientTimestamp!!) + syncMessage.deleteForMe != null -> handleSynchronizeDeleteForMe(context, syncMessage.deleteForMe!!, envelope.clientTimestamp!!, earlyMessageCacheEntry) + syncMessage.attachmentBackfillRequest != null -> handleSynchronizeAttachmentBackfillRequest(syncMessage.attachmentBackfillRequest!!, envelope.clientTimestamp!!) + syncMessage.attachmentBackfillResponse != null -> warn(envelope.clientTimestamp!!, "Contains a backfill response, but we don't handle these!") + else -> warn(envelope.clientTimestamp!!, "Contains no known sync types...") } } @@ -196,7 +196,7 @@ object SyncMessageProcessor { threadRecipient: Recipient, 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 { handlePniIdentityKeys(envelope, sent) @@ -212,42 +212,42 @@ object SyncMessageProcessor { } if (sent.isRecipientUpdate == true) { - handleGroupRecipientUpdate(sent, envelope.timestamp!!) + handleGroupRecipientUpdate(sent, envelope.clientTimestamp!!) return } val dataMessage = if (sent.message != null) { sent.message!! } else { - warn(envelope.timestamp!!, "Sync message missing nested message to sync") + warn(envelope.clientTimestamp!!, "Sync message missing nested message to sync") return } val groupId: GroupId.V2? = if (dataMessage.hasGroupContext) GroupId.v2(dataMessage.groupV2!!.groupMasterKey) else 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 } } var threadId: Long = -1 when { - dataMessage.isEndSession -> threadId = handleSynchronizeSentEndSessionMessage(context, sent, envelope.timestamp!!) + dataMessage.isEndSession -> threadId = handleSynchronizeSentEndSessionMessage(context, sent, envelope.clientTimestamp!!) dataMessage.isGroupV2Update -> { handleSynchronizeSentGv2Update(context, envelope, sent) threadId = SignalDatabase.threads.getOrCreateThreadIdFor(getSyncMessageDestination(sent)) } 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.storyContext != null -> threadId = handleSynchronizeSentStoryReply(sent, envelope.timestamp!!) + dataMessage.storyContext != null -> threadId = handleSynchronizeSentStoryReply(sent, envelope.clientTimestamp!!) dataMessage.reaction != null -> { DataMessageProcessor.handleReaction(context, envelope, dataMessage, senderRecipient.id, earlyMessageCacheEntry) threadId = SignalDatabase.threads.getOrCreateThreadIdFor(getSyncMessageDestination(sent)) } 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.pollVote != null -> { DataMessageProcessor.handlePollVote(context, envelope, dataMessage, senderRecipient, earlyMessageCacheEntry) @@ -264,11 +264,11 @@ object SyncMessageProcessor { DataMessageProcessor.handleAdminRemoteDelete(context, envelope, dataMessage, senderRecipient, threadRecipient, earlyMessageCacheEntry) 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)) { - DataMessageProcessor.handleUnknownGroupMessage(envelope.timestamp!!, dataMessage.groupV2!!) + DataMessageProcessor.handleUnknownGroupMessage(envelope.clientTimestamp!!, dataMessage.groupV2!!) } if (dataMessage.profileKey.isNotEmpty()) { @@ -284,7 +284,7 @@ object SyncMessageProcessor { } 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) } @@ -308,16 +308,16 @@ object SyncMessageProcessor { val address = SignalProtocolAddress(pni.toString(), SignalServiceAddress.DEFAULT_DEVICE_ID) 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 } 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()) AppDependencies.protocolStore.aci().identities().saveIdentity(address, identityKey) } 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 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) { AppDependencies.earlyMessageCache.store(senderRecipientId, targetSentTimestamp, earlyMessageCacheEntry) PushProcessEarlyMessagesJob.enqueue() @@ -358,12 +358,12 @@ object SyncMessageProcessor { } if (message.isMediaMessage) { - handleSynchronizeSentEditMediaMessage(targetMessage, toRecipient, sent, message, envelope.timestamp!!) + handleSynchronizeSentEditMediaMessage(targetMessage, toRecipient, sent, message, envelope.clientTimestamp!!) } else { - handleSynchronizeSentEditTextMessage(targetMessage, toRecipient, sent, message, envelope.timestamp!!) + handleSynchronizeSentEditTextMessage(targetMessage, toRecipient, sent, message, envelope.clientTimestamp!!) } } 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) 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) 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!!) return } @@ -686,18 +686,18 @@ object SyncMessageProcessor { @Throws(IOException::class, GroupChangeBusyException::class) 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 groupId: GroupId.V2? = dataMessage.groupV2?.groupId if (groupId == null) { - warn(envelope.timestamp!!, "GV2 update missing group id") + warn(envelope.clientTimestamp!!, "GV2 update missing group id") return } - if (MessageContentProcessor.updateGv2GroupFromServerOrP2PChange(context, envelope.timestamp!!, dataMessage.groupV2!!, SignalDatabase.groups.getGroup(groupId)) == null) { - log(envelope.timestamp!!, "Ignoring GV2 message for group we are not currently in $groupId") + if (MessageContentProcessor.updateGv2GroupFromServerOrP2PChange(context, envelope.clientTimestamp!!, dataMessage.groupV2!!, SignalDatabase.groups.getGroup(groupId)) == null) { + log(envelope.clientTimestamp!!, "Ignoring GV2 message for group we are not currently in $groupId") } } @@ -1764,7 +1764,7 @@ object SyncMessageProcessor { sent: Sent, senderRecipient: Recipient ): Long { - log(envelope.timestamp!!, "Synchronize sent poll creation message.") + log(envelope.clientTimestamp!!, "Synchronize sent poll creation message.") val recipient = getSyncMessageDestination(sent) val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient) @@ -1795,7 +1795,7 @@ object SyncMessageProcessor { 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) @@ -1814,7 +1814,7 @@ object SyncMessageProcessor { senderRecipient: Recipient, earlyMessageCacheEntry: EarlyMessageCacheEntry? ): Long { - log(envelope.timestamp!!, "Synchronize sent poll terminate message") + log(envelope.clientTimestamp!!, "Synchronize sent poll terminate message") val recipient = getSyncMessageDestination(sent) val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient) @@ -1827,7 +1827,7 @@ object SyncMessageProcessor { val pollTerminate = message.pollTerminate!! val targetMessage = SignalDatabase.messages.getMessageFor(pollTerminate.targetSentTimestamp!!, Recipient.self().id) 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) { AppDependencies.earlyMessageCache.store(senderRecipient.id, pollTerminate.targetSentTimestamp!!, earlyMessageCacheEntry) PushProcessEarlyMessagesJob.enqueue() @@ -1836,7 +1836,7 @@ object SyncMessageProcessor { } val poll = SignalDatabase.polls.getPoll(targetMessage.id) 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 } @@ -1857,7 +1857,7 @@ object SyncMessageProcessor { val messageId = SignalDatabase.messages.insertMessageOutbox(outgoingMessage, threadId, false, receiptStatus, null).messageId 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) { SignalDatabase.messages.markExpireStarted(messageId, sent.expirationStartTimestamp ?: 0) @@ -1874,7 +1874,7 @@ object SyncMessageProcessor { senderRecipient: Recipient, earlyMessageCacheEntry: EarlyMessageCacheEntry? ): Long { - log(envelope.timestamp!!, "Synchronize pinned message") + log(envelope.clientTimestamp!!, "Synchronize pinned message") val recipient = getSyncMessageDestination(sent) val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient) @@ -1887,14 +1887,14 @@ object SyncMessageProcessor { val pinMessage = message.pinMessage!! val targetAuthorServiceId: ServiceId = ACI.parseOrThrow(pinMessage.targetAuthorAciBinary!!) if (targetAuthorServiceId.isUnknown) { - warn(envelope.timestamp!!, "Unknown author") + warn(envelope.clientTimestamp!!, "Unknown author") return -1 } val targetAuthor = Recipient.externalPush(targetAuthorServiceId) val targetMessage = SignalDatabase.messages.getMessageFor(pinMessage.targetSentTimestamp!!, targetAuthor.id) 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) { AppDependencies.earlyMessageCache.store(senderRecipient.id, pinMessage.targetSentTimestamp!!, earlyMessageCacheEntry) PushProcessEarlyMessagesJob.enqueue() @@ -1903,12 +1903,12 @@ object SyncMessageProcessor { } if (targetMessage.hasGiftBadge()) { - warn(envelope.timestamp!!, "Cannot pin gift badge") + warn(envelope.clientTimestamp!!, "Cannot pin gift badge") return -1 } if (targetMessage.isRemoteDelete) { - warn(envelope.timestamp!!, "Cannot pin deleted message") + warn(envelope.clientTimestamp!!, "Cannot pin deleted message") return -1 } @@ -1924,7 +1924,7 @@ object SyncMessageProcessor { val messageId = SignalDatabase.messages.insertMessageOutbox(outgoingMessage, threadId, false, GroupReceiptTable.STATUS_UNKNOWN, null).messageId 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) { SignalDatabase.messages.markExpireStarted(messageId, sent.expirationStartTimestamp ?: 0) diff --git a/lib/libsignal-service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java b/lib/libsignal-service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java index 1385f57841..562a2ac764 100644 --- a/lib/libsignal-service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java +++ b/lib/libsignal-service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java @@ -112,7 +112,6 @@ import org.whispersystems.signalservice.internal.push.OutgoingPushMessage; import org.whispersystems.signalservice.internal.push.OutgoingPushMessageList; import org.whispersystems.signalservice.internal.push.PniSignatureMessage; 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.PushServiceSocket; import org.whispersystems.signalservice.internal.push.ReceiptMessage; @@ -1602,8 +1601,6 @@ public class SignalServiceMessageSender { configurationMessage.linkPreviews(configuration.getLinkPreviews().get()); } - configurationMessage.provisioningVersion(ProvisioningVersion.CURRENT.getValue()); - return container.syncMessage(syncMessage.configuration(configurationMessage.build()).build()).build(); } diff --git a/lib/libsignal-service/src/main/java/org/whispersystems/signalservice/api/crypto/EnvelopeContent.java b/lib/libsignal-service/src/main/java/org/whispersystems/signalservice/api/crypto/EnvelopeContent.java index 1d87bb3916..6e5eace919 100644 --- a/lib/libsignal-service/src/main/java/org/whispersystems/signalservice/api/crypto/EnvelopeContent.java +++ b/lib/libsignal-service/src/main/java/org/whispersystems/signalservice/api/crypto/EnvelopeContent.java @@ -104,8 +104,8 @@ public interface EnvelopeContent { int type; switch (message.getType()) { - case CiphertextMessage.PREKEY_TYPE: type = Type.PREKEY_BUNDLE.getValue(); break; - case CiphertextMessage.WHISPER_TYPE: type = Type.CIPHERTEXT.getValue(); break; + case CiphertextMessage.PREKEY_TYPE: type = Type.PREKEY_MESSAGE.getValue(); break; + case CiphertextMessage.WHISPER_TYPE: type = Type.DOUBLE_RATCHET.getValue(); break; default: throw new AssertionError("Bad type: " + message.getType()); } diff --git a/lib/libsignal-service/src/main/java/org/whispersystems/signalservice/api/crypto/SignalServiceCipher.java b/lib/libsignal-service/src/main/java/org/whispersystems/signalservice/api/crypto/SignalServiceCipher.java index b6b5939d14..0bb3981fbe 100644 --- a/lib/libsignal-service/src/main/java/org/whispersystems/signalservice/api/crypto/SignalServiceCipher.java +++ b/lib/libsignal-service/src/main/java/org/whispersystems/signalservice/api/crypto/SignalServiceCipher.java @@ -187,25 +187,25 @@ public class SignalServiceCipher { throw new InvalidMessageStructureException("Non-UD envelope is missing a UUID!"); } - if (envelope.type == Envelope.Type.PREKEY_BUNDLE) { - SignalProtocolAddress sourceAddress = new SignalProtocolAddress(sourceServiceId.toString(), envelope.sourceDevice); + if (envelope.type == Envelope.Type.PREKEY_MESSAGE) { + SignalProtocolAddress sourceAddress = new SignalProtocolAddress(sourceServiceId.toString(), envelope.sourceDeviceId); SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress)); 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; signalProtocolStore.clearSenderKeySharedWith(Collections.singleton(sourceAddress)); - } else if (envelope.type == Envelope.Type.CIPHERTEXT) { - SignalProtocolAddress sourceAddress = new SignalProtocolAddress(sourceServiceId.toString(), envelope.sourceDevice); + } else if (envelope.type == Envelope.Type.DOUBLE_RATCHET) { + SignalProtocolAddress sourceAddress = new SignalProtocolAddress(sourceServiceId.toString(), envelope.sourceDeviceId); SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress)); 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; } else if (envelope.type == Envelope.Type.PLAINTEXT_CONTENT) { 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; } else if (envelope.type == Envelope.Type.UNIDENTIFIED_SENDER) { 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; 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; } @@ -226,7 +226,7 @@ public class SignalServiceCipher { } 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 { throw new InvalidMetadataMessageException("Unknown type: " + envelope.type); } @@ -236,21 +236,21 @@ public class SignalServiceCipher { return new Plaintext(metadata, data, ciphertextMessageType); } catch (DuplicateMessageException e) { - throw new ProtocolDuplicateMessageException(e, sourceServiceId.toString(), envelope.sourceDevice); + throw new ProtocolDuplicateMessageException(e, sourceServiceId.toString(), envelope.sourceDeviceId); } catch (LegacyMessageException e) { - throw new ProtocolLegacyMessageException(e, sourceServiceId.toString(), envelope.sourceDevice); + throw new ProtocolLegacyMessageException(e, sourceServiceId.toString(), envelope.sourceDeviceId); } catch (InvalidMessageException e) { - throw new ProtocolInvalidMessageException(e, sourceServiceId.toString(), envelope.sourceDevice); + throw new ProtocolInvalidMessageException(e, sourceServiceId.toString(), envelope.sourceDeviceId); } catch (InvalidKeyIdException e) { - throw new ProtocolInvalidKeyIdException(e, sourceServiceId.toString(), envelope.sourceDevice); + throw new ProtocolInvalidKeyIdException(e, sourceServiceId.toString(), envelope.sourceDeviceId); } catch (InvalidKeyException e) { - throw new ProtocolInvalidKeyException(e, sourceServiceId.toString(), envelope.sourceDevice); + throw new ProtocolInvalidKeyException(e, sourceServiceId.toString(), envelope.sourceDeviceId); } catch (UntrustedIdentityException e) { - throw new ProtocolUntrustedIdentityException(e, sourceServiceId.toString(), envelope.sourceDevice); + throw new ProtocolUntrustedIdentityException(e, sourceServiceId.toString(), envelope.sourceDeviceId); } catch (InvalidVersionException e) { - throw new ProtocolInvalidVersionException(e, sourceServiceId.toString(), envelope.sourceDevice); + throw new ProtocolInvalidVersionException(e, sourceServiceId.toString(), envelope.sourceDeviceId); } catch (NoSessionException e) { - throw new ProtocolNoSessionException(e, sourceServiceId.toString(), envelope.sourceDevice); + throw new ProtocolNoSessionException(e, sourceServiceId.toString(), envelope.sourceDeviceId); } } diff --git a/lib/libsignal-service/src/main/java/org/whispersystems/signalservice/api/messages/EnvelopeContentValidator.kt b/lib/libsignal-service/src/main/java/org/whispersystems/signalservice/api/messages/EnvelopeContentValidator.kt index 33ab462fb0..95481e0043 100644 --- a/lib/libsignal-service/src/main/java/org/whispersystems/signalservice/api/messages/EnvelopeContentValidator.kt +++ b/lib/libsignal-service/src/main/java/org/whispersystems/signalservice/api/messages/EnvelopeContentValidator.kt @@ -83,8 +83,8 @@ object EnvelopeContentValidator { return Result.Invalid("[DataMessage] Missing timestamp!") } - if (dataMessage.timestamp != envelope.timestamp) { - return Result.Invalid("[DataMessage] Timestamps don't match! envelope: ${envelope.timestamp}, content: ${dataMessage.timestamp}") + if (dataMessage.timestamp != envelope.clientTimestamp) { + 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()) { @@ -276,8 +276,8 @@ object EnvelopeContentValidator { private fun validateTypingMessage(envelope: Envelope, typingMessage: TypingMessage): Result { return if (typingMessage.timestamp == null) { return Result.Invalid("[TypingMessage] Missing timestamp!") - } else if (typingMessage.timestamp != envelope.timestamp) { - Result.Invalid("[TypingMessage] Timestamps don't match! envelope: ${envelope.timestamp}, content: ${typingMessage.timestamp}") + } else if (typingMessage.timestamp != envelope.clientTimestamp) { + Result.Invalid("[TypingMessage] Timestamps don't match! envelope: ${envelope.clientTimestamp}, content: ${typingMessage.timestamp}") } else if (typingMessage.action == null) { Result.Invalid("[TypingMessage] Missing action!") } else { diff --git a/lib/libsignal-service/src/main/protowire/SignalService.proto b/lib/libsignal-service/src/main/protowire/SignalService.proto index dfffccfe92..0089a163c5 100644 --- a/lib/libsignal-service/src/main/protowire/SignalService.proto +++ b/lib/libsignal-service/src/main/protowire/SignalService.proto @@ -13,23 +13,79 @@ option java_outer_classname = "SignalServiceProtos"; message Envelope { enum Type { 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 "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)) - SENDERKEY_MESSAGE = 7; // legacyMessage => [] AND content => (version byte | SenderKeyMessage) - PLAINTEXT_CONTENT = 8; // legacyMessage => [] AND content => (marker byte | Content) + + /** + * A prekey message begins a new Signal session. The `content` of a prekey + * message is a superset of a double-ratchet message's `content` and + * 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; reserved 2; // formerly optional string sourceE164 = 2; optional string sourceServiceId = 11; - optional uint32 sourceDevice = 7; + optional uint32 sourceDeviceId = 7; optional string destinationServiceId = 13; 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 optional bytes content = 8; // Contains an encrypted Content optional string serverGuid = 9; @@ -48,17 +104,20 @@ message Envelope { } message Content { - optional DataMessage dataMessage = 1; - optional SyncMessage syncMessage = 2; - optional CallMessage callMessage = 3; - optional NullMessage nullMessage = 4; - optional ReceiptMessage receiptMessage = 5; - optional TypingMessage typingMessage = 6; + oneof content { + DataMessage dataMessage = 1; + SyncMessage syncMessage = 2; + CallMessage callMessage = 3; + NullMessage nullMessage = 4; + ReceiptMessage receiptMessage = 5; + TypingMessage typingMessage = 6; + bytes /* DecryptionErrorMessage */ decryptionErrorMessage = 8; + StoryMessage storyMessage = 9; + EditMessage editMessage = 11; + } + optional bytes /* SenderKeyDistributionMessage */ senderKeyDistributionMessage = 7; - optional bytes /* DecryptionErrorMessage */ decryptionErrorMessage = 8; - optional StoryMessage storyMessage = 9; optional PniSignatureMessage pniSignatureMessage = 10; - optional EditMessage editMessage = 11; } message CallMessage { @@ -331,8 +390,8 @@ message DataMessage { message PollVote { optional bytes targetAuthorAciBinary = 1; optional uint64 targetSentTimestamp = 2; - repeated uint32 optionIndexes = 3; // must be in the range [0, options.length) from the PollCreate - optional uint32 voteCount = 4; // increment this by 1 each time you vote on a given poll + repeated uint32 optionIndexes = 3; + optional uint32 voteCount = 4; } message PinMessage { @@ -441,6 +500,12 @@ message TextAttachment { } 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 endColor = 2; // deprecated: this field will be removed in a future release. optional uint32 angle = 3; // degrees @@ -553,7 +618,7 @@ message SyncMessage { optional bool unidentifiedDeliveryIndicators = 2; optional bool typingIndicators = 3; reserved /* linkPreviews */ 4; - optional uint32 provisioningVersion = 5; + reserved /* provisioningVersion */ 5; optional bool linkPreviews = 6; } @@ -688,7 +753,7 @@ message SyncMessage { optional bytes rootKey = 1; optional bytes adminPasskey = 2; optional Type type = 3; // defaults to UPDATE - reserved 4; // was epoch field, never used + reserved /*epoch*/ 4; } message CallLogEvent { @@ -785,31 +850,40 @@ message SyncMessage { } } - optional Sent sent = 1; - optional Contacts contacts = 2; + oneof content { + 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; - 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; - optional Blocked blocked = 6; - optional Verified verified = 7; - optional Configuration configuration = 9; - optional bytes padding = 8; 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; + reserved /*pniIdentity*/ 17; - optional PniChangeNumber pniChangeNumber = 18; - optional CallEvent callEvent = 19; - optional CallLinkUpdate callLinkUpdate = 20; - optional CallLogEvent callLogEvent = 21; - optional DeleteForMe deleteForMe = 22; - optional DeviceNameChange deviceNameChange = 23; - optional AttachmentBackfillRequest attachmentBackfillRequest = 24; - optional AttachmentBackfillResponse attachmentBackfillResponse = 25; + + optional bytes padding = 8; } message AttachmentPointer { diff --git a/lib/libsignal-service/src/test/java/org/signal/core/util/BuildSizeTreeTest.kt b/lib/libsignal-service/src/test/java/org/signal/core/util/BuildSizeTreeTest.kt index 513b33953b..b3f8b83045 100644 --- a/lib/libsignal-service/src/test/java/org/signal/core/util/BuildSizeTreeTest.kt +++ b/lib/libsignal-service/src/test/java/org/signal/core/util/BuildSizeTreeTest.kt @@ -16,7 +16,7 @@ import org.whispersystems.signalservice.internal.push.BodyRange import org.whispersystems.signalservice.internal.push.Content import org.whispersystems.signalservice.internal.push.DataMessage import org.whispersystems.signalservice.internal.push.GroupContextV2 -import org.whispersystems.signalservice.internal.push.SyncMessage +import org.whispersystems.signalservice.internal.push.PniSignatureMessage class BuildSizeTreeTest { @@ -136,12 +136,12 @@ class BuildSizeTreeTest { fun `multiple top-level fields are all included`() { val msg = Content( dataMessage = DataMessage(body = "hi"), - syncMessage = SyncMessage() + pniSignatureMessage = PniSignatureMessage() ) val tree = msg.buildSizeTree("Content") assertThat(tree).contains("dataMessage(") - assertThat(tree).contains("syncMessage(") + assertThat(tree).contains("pniSignatureMessage(") } @Test diff --git a/lib/libsignal-service/src/test/java/org/whispersystems/signalservice/api/messages/EnvelopeContentValidatorTest.kt b/lib/libsignal-service/src/test/java/org/whispersystems/signalservice/api/messages/EnvelopeContentValidatorTest.kt index 27275ecd5f..6c59e8a1f6 100644 --- a/lib/libsignal-service/src/test/java/org/whispersystems/signalservice/api/messages/EnvelopeContentValidatorTest.kt +++ b/lib/libsignal-service/src/test/java/org/whispersystems/signalservice/api/messages/EnvelopeContentValidatorTest.kt @@ -23,7 +23,7 @@ class EnvelopeContentValidatorTest { @Test fun `validate - ensure mismatched timestamps are marked invalid`() { val envelope = Envelope( - timestamp = 1234 + clientTimestamp = 1234 ) val content = Content( @@ -172,11 +172,10 @@ class EnvelopeContentValidatorTest { fun `validate - plaintext content via envelope type with unexpected DataMessage is invalid`() { val envelope = Envelope( type = Envelope.Type.PLAINTEXT_CONTENT, - timestamp = 1234 + clientTimestamp = 1234 ) val content = Content( - decryptionErrorMessage = createValidDecryptionErrorMessage(), 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`() { val envelope = Envelope( type = Envelope.Type.UNIDENTIFIED_SENDER, - timestamp = 1234 + clientTimestamp = 1234 ) val content = Content( - decryptionErrorMessage = createValidDecryptionErrorMessage(), dataMessage = DataMessage(timestamp = 1234) ) @@ -231,7 +229,6 @@ class EnvelopeContentValidatorTest { ) val content = Content( - decryptionErrorMessage = createValidDecryptionErrorMessage(), syncMessage = org.whispersystems.signalservice.internal.push.SyncMessage() ) @@ -242,8 +239,8 @@ class EnvelopeContentValidatorTest { @Test fun `validate - regular encrypted message is not subject to plaintext validation`() { val envelope = Envelope( - type = Envelope.Type.CIPHERTEXT, - timestamp = 1234 + type = Envelope.Type.DOUBLE_RATCHET, + clientTimestamp = 1234 ) val content = Content( diff --git a/microbenchmark/src/androidTest/java/org/signal/util/SignalClient.kt b/microbenchmark/src/androidTest/java/org/signal/util/SignalClient.kt index a93e5842e3..f06f2552bb 100644 --- a/microbenchmark/src/androidTest/java/org/signal/util/SignalClient.kt +++ b/microbenchmark/src/androidTest/java/org/signal/util/SignalClient.kt @@ -104,9 +104,9 @@ class SignalClient { return Envelope( sourceServiceId = aci.toString(), - sourceDevice = 1, + sourceDeviceId = 1, destinationServiceId = to.aci.toString(), - timestamp = sentTimestamp, + clientTimestamp = sentTimestamp, serverTimestamp = sentTimestamp, serverGuid = serviceGuid.toString(), type = Envelope.Type.fromValue(outgoingPushMessage.type), @@ -139,9 +139,9 @@ class SignalClient { return Envelope( sourceServiceId = aci.toString(), - sourceDevice = 1, + sourceDeviceId = 1, destinationServiceId = to.aci.toString(), - timestamp = sentTimestamp, + clientTimestamp = sentTimestamp, serverTimestamp = sentTimestamp, serverGuid = serverGuid.toString(), type = Envelope.Type.fromValue(outgoingPushMessage.type),