diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java index e32e7b73d1..c8613dc411 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java @@ -197,19 +197,23 @@ public final class MessageContentProcessor { Optional optionalSmsMessageId = smsMessageId > 0 ? Optional.of(smsMessageId) : Optional.absent(); if (messageState == MessageState.DECRYPTED_OK) { - handleMessage(content, timestamp, optionalSmsMessageId); if (content != null) { + Recipient senderRecipient = Recipient.externalHighTrustPush(context, content.getSender()); + + handleMessage(content, timestamp, senderRecipient, optionalSmsMessageId); + Optional> earlyContent = ApplicationDependencies.getEarlyMessageCache() - .retrieve(Recipient.externalPush(context, content.getSender()).getId(), - content.getTimestamp()); + .retrieve(senderRecipient.getId(), content.getTimestamp()); if (earlyContent.isPresent()) { log(String.valueOf(content.getTimestamp()), "Found " + earlyContent.get().size() + " dependent item(s) that were retrieved earlier. Processing."); for (SignalServiceContent earlyItem : earlyContent.get()) { - handleMessage(earlyItem, timestamp, Optional.absent()); + handleMessage(earlyItem, timestamp, senderRecipient, Optional.absent()); } } + } else { + warn("null", "Null content. Ignoring message."); } } else if (exceptionMetadata != null) { handleExceptionMessage(messageState, exceptionMetadata, timestamp, optionalSmsMessageId); @@ -220,20 +224,19 @@ public final class MessageContentProcessor { } } - private void handleMessage(@Nullable SignalServiceContent content, long timestamp, @NonNull Optional smsMessageId) + private void handleMessage(@NonNull SignalServiceContent content, long timestamp, @NonNull Recipient senderRecipient, @NonNull Optional smsMessageId) throws IOException, GroupChangeBusyException { try { - GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context); + Recipient threadRecipient = getMessageDestination(content); - if (content == null || shouldIgnore(content)) { - log(content != null ? String.valueOf(content.getTimestamp()) : "null", "Ignoring message."); + if (shouldIgnore(content, senderRecipient, threadRecipient)) { + log(content.getTimestamp(), "Ignoring message."); return; } - RecipientId senderId = RecipientId.fromHighTrust(content.getSender()); - PendingRetryReceiptModel pending = ApplicationDependencies.getPendingRetryReceiptCache().get(senderId, content.getTimestamp()); - long receivedTime = handlePendingRetry(pending, content); + PendingRetryReceiptModel pending = ApplicationDependencies.getPendingRetryReceiptCache().get(senderRecipient.getId(), content.getTimestamp()); + long receivedTime = handlePendingRetry(pending, content, threadRecipient); log(String.valueOf(content.getTimestamp()), "Beginning message processing."); @@ -242,13 +245,14 @@ public final class MessageContentProcessor { } if (content.getDataMessage().isPresent()) { + GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context); SignalServiceDataMessage message = content.getDataMessage().get(); boolean isMediaMessage = message.getAttachments().isPresent() || message.getQuote().isPresent() || message.getSharedContacts().isPresent() || message.getPreviews().isPresent() || message.getSticker().isPresent() || message.getMentions().isPresent(); Optional groupId = GroupUtil.idFromGroupContext(message.getGroupContext()); boolean isGv2Message = groupId.isPresent() && groupId.get().isV2(); if (isGv2Message) { - if (handleGv2PreProcessing(groupId.orNull().requireV2(), content, content.getDataMessage().get().getGroupContext().get().getGroupV2().get())) { + if (handleGv2PreProcessing(groupId.orNull().requireV2(), content, content.getDataMessage().get().getGroupContext().get().getGroupV2().get(), senderRecipient)) { return; } } @@ -256,41 +260,39 @@ public final class MessageContentProcessor { MessageId messageId = null; if (isInvalidMessage(message)) handleInvalidMessage(content.getSender(), content.getSenderDevice(), groupId, content.getTimestamp(), smsMessageId); - else if (message.isEndSession()) messageId = handleEndSessionMessage(content, smsMessageId); - else if (message.isGroupV1Update()) handleGroupV1Message(content, message, smsMessageId, groupId.get().requireV1(), receivedTime); - else if (message.isExpirationUpdate()) messageId = handleExpirationUpdate(content, message, smsMessageId, groupId, receivedTime); - else if (message.getReaction().isPresent()) messageId = handleReaction(content, message); - else if (message.getRemoteDelete().isPresent()) messageId = handleRemoteDelete(content, message); - else if (message.getPayment().isPresent()) handlePayment(content, message); - else if (isMediaMessage) messageId = handleMediaMessage(content, message, smsMessageId, receivedTime); - else if (message.getBody().isPresent()) messageId = handleTextMessage(content, message, smsMessageId, groupId, receivedTime); - else if (Build.VERSION.SDK_INT > 19 && message.getGroupCallUpdate().isPresent()) handleGroupCallUpdateMessage(content, message, groupId); + else if (message.isEndSession()) messageId = handleEndSessionMessage(content, smsMessageId, senderRecipient); + else if (message.isGroupV1Update()) handleGroupV1Message(content, message, smsMessageId, groupId.get().requireV1(), senderRecipient, threadRecipient, receivedTime); + else if (message.isExpirationUpdate()) messageId = handleExpirationUpdate(content, message, smsMessageId, groupId, senderRecipient, threadRecipient, receivedTime); + else if (message.getReaction().isPresent()) messageId = handleReaction(content, message, senderRecipient); + else if (message.getRemoteDelete().isPresent()) messageId = handleRemoteDelete(content, message, senderRecipient); + else if (message.getPayment().isPresent()) handlePayment(content, message, senderRecipient); + else if (isMediaMessage) messageId = handleMediaMessage(content, message, smsMessageId, senderRecipient, threadRecipient, receivedTime); + else if (message.getBody().isPresent()) messageId = handleTextMessage(content, message, smsMessageId, groupId, senderRecipient, threadRecipient, receivedTime); + else if (Build.VERSION.SDK_INT > 19 && message.getGroupCallUpdate().isPresent()) handleGroupCallUpdateMessage(content, message, groupId, senderRecipient); if (groupId.isPresent() && groupDatabase.isUnknownGroup(groupId.get())) { - handleUnknownGroupMessage(content, message.getGroupContext().get()); + handleUnknownGroupMessage(content, message.getGroupContext().get(), senderRecipient); } if (message.getProfileKey().isPresent()) { - handleProfileKey(content, message.getProfileKey().get()); + handleProfileKey(content, message.getProfileKey().get(), senderRecipient); } if (content.isNeedsReceipt() && messageId != null) { handleNeedsDeliveryReceipt(content, message, messageId); } else if (!content.isNeedsReceipt()) { - Recipient sender = getMessageDestination(content, message); - - if (RecipientUtil.shouldHaveProfileKey(context, sender)) { - Log.w(TAG, "Received an unsealed sender message from " + sender.getId() + ", but they should already have our profile key. Correcting."); + if (RecipientUtil.shouldHaveProfileKey(context, threadRecipient)) { + Log.w(TAG, "Received an unsealed sender message from " + senderRecipient.getId() + ", but they should already have our profile key. Correcting."); if (groupId.isPresent() && groupId.get().isV2()) { Log.i(TAG, "Message was to a GV2 group. Ensuring our group profile keys are up to date."); ApplicationDependencies.getJobManager().startChain(new RefreshAttributesJob(false)) .then(GroupV2UpdateSelfProfileKeyJob.withQueueLimits(groupId.get().requireV2())) .enqueue(); - } else if (!sender.isGroup()) { + } else if (!threadRecipient.isGroup()) { Log.i(TAG, "Message was to a 1:1. Ensuring this user has our profile key."); ApplicationDependencies.getJobManager().startChain(new RefreshAttributesJob(false)) - .then(ProfileKeySendJob.create(context, DatabaseFactory.getThreadDatabase(context).getThreadIdFor(sender), true)) + .then(ProfileKeySendJob.create(context, DatabaseFactory.getThreadDatabase(context).getThreadIdFor(threadRecipient), true)) .enqueue(); } } @@ -300,9 +302,9 @@ public final class MessageContentProcessor { SignalServiceSyncMessage syncMessage = content.getSyncMessage().get(); - if (syncMessage.getSent().isPresent()) handleSynchronizeSentMessage(content, syncMessage.getSent().get()); + if (syncMessage.getSent().isPresent()) handleSynchronizeSentMessage(content, syncMessage.getSent().get(), senderRecipient); else if (syncMessage.getRequest().isPresent()) handleSynchronizeRequestMessage(syncMessage.getRequest().get()); - else if (syncMessage.getRead().isPresent()) handleSynchronizeReadMessage(syncMessage.getRead().get(), content.getTimestamp()); + else if (syncMessage.getRead().isPresent()) handleSynchronizeReadMessage(syncMessage.getRead().get(), content.getTimestamp(), senderRecipient); else if (syncMessage.getViewed().isPresent()) handleSynchronizeViewedMessage(syncMessage.getViewed().get(), content.getTimestamp()); else if (syncMessage.getViewOnceOpen().isPresent()) handleSynchronizeViewOnceOpenMessage(syncMessage.getViewOnceOpen().get(), content.getTimestamp()); else if (syncMessage.getVerified().isPresent()) handleSynchronizeVerifiedMessage(syncMessage.getVerified().get()); @@ -324,29 +326,29 @@ public final class MessageContentProcessor { return; } - if (message.getOfferMessage().isPresent()) handleCallOfferMessage(content, message.getOfferMessage().get(), smsMessageId); - else if (message.getAnswerMessage().isPresent()) handleCallAnswerMessage(content, message.getAnswerMessage().get()); - else if (message.getIceUpdateMessages().isPresent()) handleCallIceUpdateMessage(content, message.getIceUpdateMessages().get()); - else if (message.getHangupMessage().isPresent()) handleCallHangupMessage(content, message.getHangupMessage().get(), smsMessageId); - else if (message.getBusyMessage().isPresent()) handleCallBusyMessage(content, message.getBusyMessage().get()); - else if (message.getOpaqueMessage().isPresent()) handleCallOpaqueMessage(content, message.getOpaqueMessage().get()); + if (message.getOfferMessage().isPresent()) handleCallOfferMessage(content, message.getOfferMessage().get(), smsMessageId, senderRecipient); + else if (message.getAnswerMessage().isPresent()) handleCallAnswerMessage(content, message.getAnswerMessage().get(), senderRecipient); + else if (message.getIceUpdateMessages().isPresent()) handleCallIceUpdateMessage(content, message.getIceUpdateMessages().get(), senderRecipient); + else if (message.getHangupMessage().isPresent()) handleCallHangupMessage(content, message.getHangupMessage().get(), smsMessageId, senderRecipient); + else if (message.getBusyMessage().isPresent()) handleCallBusyMessage(content, message.getBusyMessage().get(), senderRecipient); + else if (message.getOpaqueMessage().isPresent()) handleCallOpaqueMessage(content, message.getOpaqueMessage().get(), senderRecipient); } else if (content.getReceiptMessage().isPresent()) { SignalServiceReceiptMessage message = content.getReceiptMessage().get(); - if (message.isReadReceipt()) handleReadReceipt(content, message); - else if (message.isDeliveryReceipt()) handleDeliveryReceipt(content, message); - else if (message.isViewedReceipt()) handleViewedReceipt(content, message); + if (message.isReadReceipt()) handleReadReceipt(content, message, senderRecipient); + else if (message.isDeliveryReceipt()) handleDeliveryReceipt(content, message, senderRecipient); + else if (message.isViewedReceipt()) handleViewedReceipt(content, message, senderRecipient); } else if (content.getTypingMessage().isPresent()) { - handleTypingMessage(content, content.getTypingMessage().get()); + handleTypingMessage(content, content.getTypingMessage().get(), senderRecipient); } else if (content.getDecryptionErrorMessage().isPresent()) { - handleRetryReceipt(content, content.getDecryptionErrorMessage().get()); + handleRetryReceipt(content, content.getDecryptionErrorMessage().get(), senderRecipient); } else if (content.getSenderKeyDistributionMessage().isPresent()) { // Already handled, here in order to prevent unrecognized message log } else { warn(String.valueOf(content.getTimestamp()), "Got unrecognized message!"); } - resetRecipientToPush(Recipient.externalPush(context, content.getSender())); + resetRecipientToPush(senderRecipient); if (pending != null) { warn(content.getTimestamp(), "Pending retry was processed. Deleting."); @@ -360,14 +362,13 @@ public final class MessageContentProcessor { } } - private long handlePendingRetry(PendingRetryReceiptModel pending, SignalServiceContent content) throws BadGroupIdException { + private long handlePendingRetry(@Nullable PendingRetryReceiptModel pending, @NonNull SignalServiceContent content, @NonNull Recipient destination) throws BadGroupIdException { long receivedTime = System.currentTimeMillis(); if (pending != null) { warn(content.getTimestamp(), "Incoming message matches a pending retry we were expecting."); - Recipient destination = getMessageDestination(content); - Long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(destination.getId()); + Long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(destination.getId()); if (threadId != null) { ThreadDatabase.ConversationMetadata metadata = DatabaseFactory.getThreadDatabase(context).getConversationMetadata(threadId); @@ -387,32 +388,31 @@ public final class MessageContentProcessor { return receivedTime; } - private void handlePayment(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message) { + private void handlePayment(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message, @NonNull Recipient senderRecipient) { if (!message.getPayment().isPresent()) { throw new AssertionError(); } if (!message.getPayment().get().getPaymentNotification().isPresent()) { - Log.w(TAG, "Ignoring payment message without notification"); + warn(content.getTimestamp(), "Ignoring payment message without notification"); return; } SignalServiceDataMessage.PaymentNotification paymentNotification = message.getPayment().get().getPaymentNotification().get(); PaymentDatabase paymentDatabase = DatabaseFactory.getPaymentDatabase(context); UUID uuid = UUID.randomUUID(); - Recipient recipient = Recipient.externalHighTrustPush(context, content.getSender()); - String queue = "Payment_" + PushProcessMessageJob.getQueueName(recipient.getId()); + String queue = "Payment_" + PushProcessMessageJob.getQueueName(senderRecipient.getId()); try { paymentDatabase.createIncomingPayment(uuid, - recipient.getId(), + senderRecipient.getId(), message.getTimestamp(), paymentNotification.getNote(), Money.MobileCoin.ZERO, Money.MobileCoin.ZERO, paymentNotification.getReceipt()); } catch (PaymentDatabase.PublicKeyConflictException e) { - Log.w(TAG, "Ignoring payment with public key already in database"); + warn(content.getTimestamp(), "Ignoring payment with public key already in database"); return; } @@ -425,7 +425,7 @@ public final class MessageContentProcessor { /** * @return True if the content should be ignored, otherwise false. */ - private boolean handleGv2PreProcessing(GroupId.V2 groupId, SignalServiceContent content, SignalServiceGroupV2 groupV2) + private boolean handleGv2PreProcessing(@NonNull GroupId.V2 groupId, @NonNull SignalServiceContent content, @NonNull SignalServiceGroupV2 groupV2, @NonNull Recipient senderRecipient) throws IOException, GroupChangeBusyException { GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context); @@ -440,8 +440,7 @@ public final class MessageContentProcessor { return true; } - Recipient sender = Recipient.externalPush(context, content.getSender()); - if (!groupDatabase.isCurrentMember(groupId, sender.getId())) { + if (!groupDatabase.isCurrentMember(groupId, senderRecipient.getId())) { log(String.valueOf(content.getTimestamp()), "Ignoring GV2 message from member not in group " + groupId); return true; } @@ -516,7 +515,7 @@ public final class MessageContentProcessor { case CORRUPT_MESSAGE: case NO_SESSION: warn(String.valueOf(timestamp), "Discovered old enqueued bad encrypted message. Scheduling reset."); - ApplicationDependencies.getJobManager().add(new AutomaticSessionResetJob(Recipient.external(context, e.sender).getId(), e.senderDevice, timestamp)); + ApplicationDependencies.getJobManager().add(new AutomaticSessionResetJob(sender.getId(), e.senderDevice, timestamp)); break; default: @@ -526,7 +525,8 @@ public final class MessageContentProcessor { private void handleCallOfferMessage(@NonNull SignalServiceContent content, @NonNull OfferMessage message, - @NonNull Optional smsMessageId) + @NonNull Optional smsMessageId, + @NonNull Recipient senderRecipient) { log(String.valueOf(content.getTimestamp()), "handleCallOfferMessage..."); @@ -534,9 +534,8 @@ public final class MessageContentProcessor { MessageDatabase database = DatabaseFactory.getSmsDatabase(context); database.markAsMissedCall(smsMessageId.get(), message.getType() == OfferMessage.Type.VIDEO_CALL); } else { - Recipient recipient = Recipient.externalHighTrustPush(context, content.getSender()); - RemotePeer remotePeer = new RemotePeer(recipient.getId()); - byte[] remoteIdentityKey = DatabaseFactory.getIdentityDatabase(context).getIdentity(recipient.getId()).transform(record -> record.getIdentityKey().serialize()).orNull(); + RemotePeer remotePeer = new RemotePeer(senderRecipient.getId()); + byte[] remoteIdentityKey = DatabaseFactory.getIdentityDatabase(context).getIdentity(senderRecipient.getId()).transform(record -> record.getIdentityKey().serialize()).orNull(); ApplicationDependencies.getSignalCallManager() .receivedOffer(new WebRtcData.CallMetadata(remotePeer, new CallId(message.getId()), content.getSenderDevice()), @@ -549,12 +548,12 @@ public final class MessageContentProcessor { } private void handleCallAnswerMessage(@NonNull SignalServiceContent content, - @NonNull AnswerMessage message) + @NonNull AnswerMessage message, + @NonNull Recipient senderRecipient) { log(String.valueOf(content), "handleCallAnswerMessage..."); - Recipient recipient = Recipient.externalHighTrustPush(context, content.getSender()); - RemotePeer remotePeer = new RemotePeer(recipient.getId()); - byte[] remoteIdentityKey = DatabaseFactory.getIdentityDatabase(context).getIdentity(recipient.getId()).transform(record -> record.getIdentityKey().serialize()).orNull(); + RemotePeer remotePeer = new RemotePeer(senderRecipient.getId()); + byte[] remoteIdentityKey = DatabaseFactory.getIdentityDatabase(context).getIdentity(senderRecipient.getId()).transform(record -> record.getIdentityKey().serialize()).orNull(); ApplicationDependencies.getSignalCallManager() .receivedAnswer(new WebRtcData.CallMetadata(remotePeer, new CallId(message.getId()), content.getSenderDevice()), @@ -563,7 +562,8 @@ public final class MessageContentProcessor { } private void handleCallIceUpdateMessage(@NonNull SignalServiceContent content, - @NonNull List messages) + @NonNull List messages, + @NonNull Recipient senderRecipient) { log(String.valueOf(content), "handleCallIceUpdateMessage... " + messages.size()); @@ -575,7 +575,7 @@ public final class MessageContentProcessor { callId = iceMessage.getId(); } - RemotePeer remotePeer = new RemotePeer(Recipient.externalHighTrustPush(context, content.getSender()).getId()); + RemotePeer remotePeer = new RemotePeer(senderRecipient.getId()); ApplicationDependencies.getSignalCallManager() .receivedIceCandidates(new WebRtcData.CallMetadata(remotePeer, new CallId(callId), content.getSenderDevice()), @@ -584,13 +584,14 @@ public final class MessageContentProcessor { private void handleCallHangupMessage(@NonNull SignalServiceContent content, @NonNull HangupMessage message, - @NonNull Optional smsMessageId) + @NonNull Optional smsMessageId, + @NonNull Recipient senderRecipient) { log(String.valueOf(content), "handleCallHangupMessage"); if (smsMessageId.isPresent()) { DatabaseFactory.getSmsDatabase(context).markAsMissedCall(smsMessageId.get(), false); } else { - RemotePeer remotePeer = new RemotePeer(Recipient.externalHighTrustPush(context, content.getSender()).getId()); + RemotePeer remotePeer = new RemotePeer(senderRecipient.getId()); ApplicationDependencies.getSignalCallManager() .receivedCallHangup(new WebRtcData.CallMetadata(remotePeer, new CallId(message.getId()), content.getSenderDevice()), @@ -599,18 +600,20 @@ public final class MessageContentProcessor { } private void handleCallBusyMessage(@NonNull SignalServiceContent content, - @NonNull BusyMessage message) + @NonNull BusyMessage message, + @NonNull Recipient senderRecipient) { log(String.valueOf(content.getTimestamp()), "handleCallBusyMessage"); - RemotePeer remotePeer = new RemotePeer(Recipient.externalHighTrustPush(context, content.getSender()).getId()); + RemotePeer remotePeer = new RemotePeer(senderRecipient.getId()); ApplicationDependencies.getSignalCallManager() .receivedCallBusy(new WebRtcData.CallMetadata(remotePeer, new CallId(message.getId()), content.getSenderDevice())); } private void handleCallOpaqueMessage(@NonNull SignalServiceContent content, - @NonNull OpaqueMessage message) + @NonNull OpaqueMessage message, + @NonNull Recipient senderRecipient) { log(String.valueOf(content.getTimestamp()), "handleCallOpaqueMessage"); @@ -620,7 +623,7 @@ public final class MessageContentProcessor { } ApplicationDependencies.getSignalCallManager() - .receivedOpaqueMessage(new WebRtcData.OpaqueMessageMetadata(Recipient.externalHighTrustPush(context, content.getSender()).requireUuid(), + .receivedOpaqueMessage(new WebRtcData.OpaqueMessageMetadata(senderRecipient.requireUuid(), message.getOpaque(), content.getSenderDevice(), messageAgeSeconds)); @@ -628,7 +631,8 @@ public final class MessageContentProcessor { private void handleGroupCallUpdateMessage(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message, - @NonNull Optional groupId) + @NonNull Optional groupId, + @NonNull Recipient senderRecipient) { if (!groupId.isPresent() || !groupId.get().isV2()) { Log.w(TAG, "Invalid group for group call update message"); @@ -638,18 +642,19 @@ public final class MessageContentProcessor { RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromPossiblyMigratedGroupId(groupId.get()); DatabaseFactory.getSmsDatabase(context).insertOrUpdateGroupCall(groupRecipientId, - RecipientId.from(content.getSender()), - content.getServerReceivedTimestamp(), - message.getGroupCallUpdate().get().getEraId()); + senderRecipient.getId(), + content.getServerReceivedTimestamp(), + message.getGroupCallUpdate().get().getEraId()); GroupCallPeekJob.enqueue(groupRecipientId); } private @Nullable MessageId handleEndSessionMessage(@NonNull SignalServiceContent content, - @NonNull Optional smsMessageId) + @NonNull Optional smsMessageId, + @NonNull Recipient senderRecipient) { MessageDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context); - IncomingTextMessage incomingTextMessage = new IncomingTextMessage(Recipient.externalHighTrustPush(context, content.getSender()).getId(), + IncomingTextMessage incomingTextMessage = new IncomingTextMessage(senderRecipient.getId(), content.getSenderDevice(), content.getTimestamp(), content.getServerReceivedTimestamp(), @@ -713,13 +718,15 @@ public final class MessageContentProcessor { @NonNull SignalServiceDataMessage message, @NonNull Optional smsMessageId, @NonNull GroupId.V1 groupId, + @NonNull Recipient senderRecipient, + @NonNull Recipient threadRecipient, long receivedTime) throws StorageFailedException, BadGroupIdException { GroupV1MessageProcessor.process(context, content, message, false); - if (message.getExpiresInSeconds() != 0 && message.getExpiresInSeconds() != getMessageDestination(content, message).getExpireMessages()) { - handleExpirationUpdate(content, message, Optional.absent(), Optional.of(groupId), receivedTime); + if (message.getExpiresInSeconds() != 0 && message.getExpiresInSeconds() != threadRecipient.getExpireMessages()) { + handleExpirationUpdate(content, message, Optional.absent(), Optional.of(groupId), senderRecipient, threadRecipient, receivedTime); } if (smsMessageId.isPresent()) { @@ -728,13 +735,14 @@ public final class MessageContentProcessor { } private void handleUnknownGroupMessage(@NonNull SignalServiceContent content, - @NonNull SignalServiceGroupContext group) + @NonNull SignalServiceGroupContext group, + @NonNull Recipient senderRecipient) throws BadGroupIdException { if (group.getGroupV1().isPresent()) { SignalServiceGroup groupV1 = group.getGroupV1().get(); if (groupV1.getType() != SignalServiceGroup.Type.REQUEST_INFO) { - ApplicationDependencies.getJobManager().add(new RequestGroupInfoJob(Recipient.externalHighTrustPush(context, content.getSender()).getId(), GroupId.v1(groupV1.getGroupId()))); + ApplicationDependencies.getJobManager().add(new RequestGroupInfoJob(senderRecipient.getId(), GroupId.v1(groupV1.getGroupId()))); } else { warn(content.getTimestamp(), "Received a REQUEST_INFO message for a group we don't know about. Ignoring."); } @@ -750,8 +758,10 @@ public final class MessageContentProcessor { @NonNull SignalServiceDataMessage message, @NonNull Optional smsMessageId, @NonNull Optional groupId, + @NonNull Recipient senderRecipient, + @NonNull Recipient threadRecipient, long receivedTime) - throws StorageFailedException, BadGroupIdException + throws StorageFailedException { if (groupId.isPresent() && groupId.get().isV2()) { warn(String.valueOf(content.getTimestamp()), "Expiration update received for GV2. Ignoring."); @@ -760,17 +770,15 @@ public final class MessageContentProcessor { int expiresInSeconds = message.getExpiresInSeconds(); Optional groupContext = message.getGroupContext(); - Recipient recipient = getMessageDestination(content, groupContext); - if (recipient.getExpireMessages() == expiresInSeconds) { + if (threadRecipient.getExpireMessages() == expiresInSeconds) { log(String.valueOf(content.getTimestamp()), "No change in message expiry for group. Ignoring."); return null; } try { MessageDatabase database = DatabaseFactory.getMmsDatabase(context); - Recipient sender = Recipient.externalHighTrustPush(context, content.getSender()); - IncomingMediaMessage mediaMessage = new IncomingMediaMessage(sender.getId(), + IncomingMediaMessage mediaMessage = new IncomingMediaMessage(senderRecipient.getId(), content.getTimestamp(), content.getServerReceivedTimestamp(), receivedTime, @@ -791,7 +799,7 @@ public final class MessageContentProcessor { Optional insertResult = database.insertSecureDecryptedMessageInbox(mediaMessage, -1); - DatabaseFactory.getRecipientDatabase(context).setExpireMessages(recipient.getId(), expiresInSeconds); + DatabaseFactory.getRecipientDatabase(context).setExpireMessages(threadRecipient.getId(), expiresInSeconds); if (smsMessageId.isPresent()) { DatabaseFactory.getSmsDatabase(context).deleteMessage(smsMessageId.get()); @@ -807,7 +815,7 @@ public final class MessageContentProcessor { return null; } - private @Nullable MessageId handleReaction(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message) { + private @Nullable MessageId handleReaction(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message, @NonNull Recipient senderRecipient) { SignalServiceDataMessage.Reaction reaction = message.getReaction().get(); if (!EmojiUtil.isEmoji(reaction.getEmoji())) { @@ -815,7 +823,6 @@ public final class MessageContentProcessor { return null; } - Recipient reactionAuthor = Recipient.externalHighTrustPush(context, content.getSender()); Recipient targetAuthor = Recipient.externalPush(context, reaction.getTargetAuthor()); MessageRecord targetMessage = DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(reaction.getTargetSentTimestamp(), targetAuthor.getId()); @@ -839,12 +846,12 @@ public final class MessageContentProcessor { Recipient threadRecipient = targetThread.getRecipient().resolve(); - if (threadRecipient.isGroup() && !threadRecipient.getParticipants().contains(reactionAuthor)) { + if (threadRecipient.isGroup() && !threadRecipient.getParticipants().contains(senderRecipient)) { warn(String.valueOf(content.getTimestamp()), "[handleReaction] Reaction author is not in the group! timestamp: " + reaction.getTargetSentTimestamp() + " author: " + targetAuthor.getId()); return null; } - if (!threadRecipient.isGroup() && !reactionAuthor.equals(threadRecipient) && !reactionAuthor.isSelf()) { + if (!threadRecipient.isGroup() && !senderRecipient.equals(threadRecipient) && !senderRecipient.isSelf()) { warn(String.valueOf(content.getTimestamp()), "[handleReaction] Reaction author is not a part of the 1:1 thread! timestamp: " + reaction.getTargetSentTimestamp() + " author: " + targetAuthor.getId()); return null; } @@ -852,10 +859,10 @@ public final class MessageContentProcessor { MessageDatabase db = targetMessage.isMms() ? DatabaseFactory.getMmsDatabase(context) : DatabaseFactory.getSmsDatabase(context); if (reaction.isRemove()) { - db.deleteReaction(targetMessage.getId(), reactionAuthor.getId()); + db.deleteReaction(targetMessage.getId(), senderRecipient.getId()); ApplicationDependencies.getMessageNotifier().updateNotification(context); } else { - ReactionRecord reactionRecord = new ReactionRecord(reaction.getEmoji(), reactionAuthor.getId(), message.getTimestamp(), System.currentTimeMillis()); + ReactionRecord reactionRecord = new ReactionRecord(reaction.getEmoji(), senderRecipient.getId(), message.getTimestamp(), System.currentTimeMillis()); db.addReaction(targetMessage.getId(), reactionRecord); ApplicationDependencies.getMessageNotifier().updateNotification(context, targetMessage.getThreadId(), false); } @@ -863,24 +870,23 @@ public final class MessageContentProcessor { return new MessageId(targetMessage.getId(), targetMessage.isMms()); } - private @Nullable MessageId handleRemoteDelete(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message) { + private @Nullable MessageId handleRemoteDelete(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message, @NonNull Recipient senderRecipient) { SignalServiceDataMessage.RemoteDelete delete = message.getRemoteDelete().get(); - Recipient sender = Recipient.externalHighTrustPush(context, content.getSender()); - MessageRecord targetMessage = DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(delete.getTargetSentTimestamp(), sender.getId()); + MessageRecord targetMessage = DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(delete.getTargetSentTimestamp(), senderRecipient.getId()); - if (targetMessage != null && RemoteDeleteUtil.isValidReceive(targetMessage, sender, content.getServerReceivedTimestamp())) { + if (targetMessage != null && RemoteDeleteUtil.isValidReceive(targetMessage, senderRecipient, content.getServerReceivedTimestamp())) { MessageDatabase db = targetMessage.isMms() ? DatabaseFactory.getMmsDatabase(context) : DatabaseFactory.getSmsDatabase(context); db.markAsRemoteDelete(targetMessage.getId()); ApplicationDependencies.getMessageNotifier().updateNotification(context, targetMessage.getThreadId(), false); return new MessageId(targetMessage.getId(), targetMessage.isMms()); } else if (targetMessage == null) { - warn(String.valueOf(content.getTimestamp()), "[handleRemoteDelete] Could not find matching message! timestamp: " + delete.getTargetSentTimestamp() + " author: " + sender.getId()); - ApplicationDependencies.getEarlyMessageCache().store(sender.getId(), delete.getTargetSentTimestamp(), content); + warn(String.valueOf(content.getTimestamp()), "[handleRemoteDelete] Could not find matching message! timestamp: " + delete.getTargetSentTimestamp() + " author: " + senderRecipient.getId()); + ApplicationDependencies.getEarlyMessageCache().store(senderRecipient.getId(), delete.getTargetSentTimestamp(), content); return null; } else { warn(String.valueOf(content.getTimestamp()), String.format(Locale.ENGLISH, "[handleRemoteDelete] Invalid remote delete! deleteTime: %d, targetTime: %d, deleteAuthor: %s, targetAuthor: %s", - content.getServerReceivedTimestamp(), targetMessage.getServerTimestamp(), sender.getId(), targetMessage.getRecipient().getId())); + content.getServerReceivedTimestamp(), targetMessage.getServerTimestamp(), senderRecipient.getId(), targetMessage.getRecipient().getId())); return null; } } @@ -952,7 +958,7 @@ public final class MessageContentProcessor { throws BadGroupIdException { RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context); - ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context); + ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context); Recipient recipient; @@ -1025,7 +1031,8 @@ public final class MessageContentProcessor { } private void handleSynchronizeSentMessage(@NonNull SignalServiceContent content, - @NonNull SentTranscriptMessage message) + @NonNull SentTranscriptMessage message, + @NonNull Recipient senderRecipient) throws StorageFailedException, BadGroupIdException, IOException, GroupChangeBusyException { log(String.valueOf(content.getTimestamp()), "Processing sent transcript for message with ID " + message.getTimestamp()); @@ -1035,7 +1042,7 @@ public final class MessageContentProcessor { if (message.getMessage().isGroupV2Message()) { GroupId.V2 groupId = GroupId.v2(message.getMessage().getGroupContext().get().getGroupV2().get().getMasterKey()); - if (handleGv2PreProcessing(groupId, content, message.getMessage().getGroupContext().get().getGroupV2().get())) { + if (handleGv2PreProcessing(groupId, content, message.getMessage().getGroupContext().get().getGroupV2().get(), senderRecipient)) { return; } } @@ -1053,16 +1060,16 @@ public final class MessageContentProcessor { handleSynchronizeSentGv2Update(content, message); threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(getSyncMessageDestination(message)); } else if (Build.VERSION.SDK_INT > 19 && message.getMessage().getGroupCallUpdate().isPresent()) { - handleGroupCallUpdateMessage(content, message.getMessage(), GroupUtil.idFromGroupContext(message.getMessage().getGroupContext())); + handleGroupCallUpdateMessage(content, message.getMessage(), GroupUtil.idFromGroupContext(message.getMessage().getGroupContext()), senderRecipient); } else if (message.getMessage().isEmptyGroupV2Message()) { warn(content.getTimestamp(), "Empty GV2 message! Doing nothing."); } else if (message.getMessage().isExpirationUpdate()) { threadId = handleSynchronizeSentExpirationUpdate(message); } else if (message.getMessage().getReaction().isPresent()) { - handleReaction(content, message.getMessage()); + handleReaction(content, message.getMessage(), senderRecipient); threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(getSyncMessageDestination(message)); } else if (message.getMessage().getRemoteDelete().isPresent()) { - handleRemoteDelete(content, message.getMessage()); + handleRemoteDelete(content, message.getMessage(), senderRecipient); } else if (message.getMessage().getAttachments().isPresent() || message.getMessage().getQuote().isPresent() || message.getMessage().getPreviews().isPresent() || message.getMessage().getSticker().isPresent() || message.getMessage().isViewOnce() || message.getMessage().getMentions().isPresent()) { threadId = handleSynchronizeSentMediaMessage(message); } else { @@ -1070,7 +1077,7 @@ public final class MessageContentProcessor { } if (message.getMessage().getGroupContext().isPresent() && groupDatabase.isUnknownGroup(GroupUtil.idFromGroupContext(message.getMessage().getGroupContext().get()))) { - handleUnknownGroupMessage(content, message.getMessage().getGroupContext().get()); + handleUnknownGroupMessage(content, message.getMessage().getGroupContext().get(), senderRecipient); } if (message.getMessage().getProfileKey().isPresent()) { @@ -1136,14 +1143,14 @@ public final class MessageContentProcessor { } } - private void handleSynchronizeReadMessage(@NonNull List readMessages, long envelopeTimestamp) + private void handleSynchronizeReadMessage(@NonNull List readMessages, long envelopeTimestamp, @NonNull Recipient senderRecipient) { Map threadToLatestRead = new HashMap<>(); for (ReadMessage readMessage : readMessages) { - List> expiringText = DatabaseFactory.getSmsDatabase(context).setTimestampRead(new SyncMessageId(Recipient.externalPush(context, readMessage.getSender()).getId(), readMessage.getTimestamp()), + List> expiringText = DatabaseFactory.getSmsDatabase(context).setTimestampRead(new SyncMessageId(senderRecipient.getId(), readMessage.getTimestamp()), envelopeTimestamp, threadToLatestRead); - List> expiringMedia = DatabaseFactory.getMmsDatabase(context).setTimestampRead(new SyncMessageId(Recipient.externalPush(context, readMessage.getSender()).getId(), readMessage.getTimestamp()), + List> expiringMedia = DatabaseFactory.getMmsDatabase(context).setTimestampRead(new SyncMessageId(senderRecipient.getId(), readMessage.getTimestamp()), envelopeTimestamp, threadToLatestRead); @@ -1210,10 +1217,12 @@ public final class MessageContentProcessor { private @Nullable MessageId handleMediaMessage(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message, @NonNull Optional smsMessageId, + @NonNull Recipient senderRecipient, + @NonNull Recipient threadRecipient, long receivedTime) - throws StorageFailedException, BadGroupIdException + throws StorageFailedException { - notifyTypingStoppedFromIncomingMessage(getMessageDestination(content, message), content.getSender(), content.getSenderDevice()); + notifyTypingStoppedFromIncomingMessage(senderRecipient, threadRecipient, content.getSenderDevice()); Optional insertResult; @@ -1227,7 +1236,7 @@ public final class MessageContentProcessor { Optional> mentions = getMentions(message.getMentions()); Optional sticker = getStickerAttachment(message.getSticker()); - IncomingMediaMessage mediaMessage = new IncomingMediaMessage(RecipientId.fromHighTrust(content.getSender()), + IncomingMediaMessage mediaMessage = new IncomingMediaMessage(senderRecipient.getId(), message.getTimestamp(), content.getServerReceivedTimestamp(), receivedTime, @@ -1414,18 +1423,18 @@ public final class MessageContentProcessor { } private void updateGroupReceiptStatus(@NonNull SentTranscriptMessage message, long messageId, @NonNull GroupId groupString) { - GroupReceiptDatabase receiptDatabase = DatabaseFactory.getGroupReceiptDatabase(context); - List messageRecipients = Stream.of(message.getRecipients()).map(address -> Recipient.externalPush(context, address)).toList(); - List members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupString, GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF); - Map localReceipts = Stream.of(receiptDatabase.getGroupReceiptInfo(messageId)) - .collect(Collectors.toMap(GroupReceiptInfo::getRecipientId, GroupReceiptInfo::getStatus)); + GroupReceiptDatabase receiptDatabase = DatabaseFactory.getGroupReceiptDatabase(context); + List messageRecipientIds = Stream.of(message.getRecipients()).map(RecipientId::from).toList(); + List members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupString, GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF); + Map localReceipts = Stream.of(receiptDatabase.getGroupReceiptInfo(messageId)) + .collect(Collectors.toMap(GroupReceiptInfo::getRecipientId, GroupReceiptInfo::getStatus)); - for (Recipient messageRecipient : messageRecipients) { + for (RecipientId messageRecipientId : messageRecipientIds) { //noinspection ConstantConditions - if (localReceipts.containsKey(messageRecipient.getId()) && localReceipts.get(messageRecipient.getId()) < GroupReceiptDatabase.STATUS_UNDELIVERED) { - receiptDatabase.update(messageRecipient.getId(), messageId, GroupReceiptDatabase.STATUS_UNDELIVERED, message.getTimestamp()); - } else if (!localReceipts.containsKey(messageRecipient.getId())) { - receiptDatabase.insert(Collections.singletonList(messageRecipient.getId()), messageId, GroupReceiptDatabase.STATUS_UNDELIVERED, message.getTimestamp()); + if (localReceipts.containsKey(messageRecipientId) && localReceipts.get(messageRecipientId) < GroupReceiptDatabase.STATUS_UNDELIVERED) { + receiptDatabase.update(messageRecipientId, messageId, GroupReceiptDatabase.STATUS_UNDELIVERED, message.getTimestamp()); + } else if (!localReceipts.containsKey(messageRecipientId)) { + receiptDatabase.insert(Collections.singletonList(messageRecipientId), messageId, GroupReceiptDatabase.STATUS_UNDELIVERED, message.getTimestamp()); } } @@ -1439,15 +1448,16 @@ public final class MessageContentProcessor { @NonNull SignalServiceDataMessage message, @NonNull Optional smsMessageId, @NonNull Optional groupId, + @NonNull Recipient senderRecipient, + @NonNull Recipient threadRecipient, long receivedTime) - throws StorageFailedException, BadGroupIdException + throws StorageFailedException { - MessageDatabase database = DatabaseFactory.getSmsDatabase(context); - String body = message.getBody().isPresent() ? message.getBody().get() : ""; - Recipient recipient = getMessageDestination(content, message); + MessageDatabase database = DatabaseFactory.getSmsDatabase(context); + String body = message.getBody().isPresent() ? message.getBody().get() : ""; - if (message.getExpiresInSeconds() != recipient.getExpireMessages()) { - handleExpirationUpdate(content, message, Optional.absent(), groupId, receivedTime); + if (message.getExpiresInSeconds() != threadRecipient.getExpireMessages()) { + handleExpirationUpdate(content, message, Optional.absent(), groupId, senderRecipient, threadRecipient, receivedTime); } Optional insertResult; @@ -1455,9 +1465,9 @@ public final class MessageContentProcessor { if (smsMessageId.isPresent() && !message.getGroupContext().isPresent()) { insertResult = Optional.of(database.updateBundleMessageBody(smsMessageId.get(), body)); } else { - notifyTypingStoppedFromIncomingMessage(recipient, content.getSender(), content.getSenderDevice()); + notifyTypingStoppedFromIncomingMessage(senderRecipient, threadRecipient, content.getSenderDevice()); - IncomingTextMessage textMessage = new IncomingTextMessage(RecipientId.fromHighTrust(content.getSender()), + IncomingTextMessage textMessage = new IncomingTextMessage(senderRecipient.getId(), content.getSenderDevice(), message.getTimestamp(), content.getServerReceivedTimestamp(), @@ -1635,15 +1645,15 @@ public final class MessageContentProcessor { } private void handleProfileKey(@NonNull SignalServiceContent content, - @NonNull byte[] messageProfileKeyBytes) + @NonNull byte[] messageProfileKeyBytes, + @NonNull Recipient senderRecipient) { RecipientDatabase database = DatabaseFactory.getRecipientDatabase(context); - Recipient recipient = Recipient.externalHighTrustPush(context, content.getSender()); - ProfileKey messageProfileKey = ProfileKeyUtil.profileKeyOrNull(messageProfileKeyBytes); + ProfileKey messageProfileKey = ProfileKeyUtil.profileKeyOrNull(messageProfileKeyBytes); if (messageProfileKey != null) { - if (database.setProfileKey(recipient.getId(), messageProfileKey)) { - ApplicationDependencies.getJobManager().add(RetrieveProfileJob.forRecipient(recipient.getId())); + if (database.setProfileKey(senderRecipient.getId(), messageProfileKey)) { + ApplicationDependencies.getJobManager().add(RetrieveProfileJob.forRecipient(senderRecipient.getId())); } } else { warn(String.valueOf(content.getTimestamp()), "Ignored invalid profile key seen in message"); @@ -1664,84 +1674,83 @@ public final class MessageContentProcessor { } private void handleViewedReceipt(@NonNull SignalServiceContent content, - @NonNull SignalServiceReceiptMessage message) + @NonNull SignalServiceReceiptMessage message, + @NonNull Recipient senderRecipient) { if (!TextSecurePreferences.isReadReceiptsEnabled(context)) { log("Ignoring viewed receipts for IDs: " + Util.join(message.getTimestamps(), ", ")); return; } - Recipient sender = Recipient.externalHighTrustPush(context, content.getSender()); - log(TAG, "Processing viewed receipts. Sender: " + sender.getId() + ", Device: " + content.getSenderDevice() + ", Timestamps: " + Util.join(message.getTimestamps(), ", ")); + log(TAG, "Processing viewed receipts. Sender: " + senderRecipient.getId() + ", Device: " + content.getSenderDevice() + ", Timestamps: " + Util.join(message.getTimestamps(), ", ")); List ids = Stream.of(message.getTimestamps()) - .map(t -> new SyncMessageId(sender.getId(), t)) + .map(t -> new SyncMessageId(senderRecipient.getId(), t)) .toList(); Collection unhandled = DatabaseFactory.getMmsSmsDatabase(context) .incrementViewedReceiptCounts(ids, content.getTimestamp()); for (SyncMessageId id : unhandled) { - warn(String.valueOf(content.getTimestamp()), "[handleViewedReceipt] Could not find matching message! timestamp: " + id.getTimetamp() + " author: " + sender.getId()); - ApplicationDependencies.getEarlyMessageCache().store(sender.getId(), id.getTimetamp(), content); + warn(String.valueOf(content.getTimestamp()), "[handleViewedReceipt] Could not find matching message! timestamp: " + id.getTimetamp() + " author: " + senderRecipient.getId()); + ApplicationDependencies.getEarlyMessageCache().store(senderRecipient.getId(), id.getTimetamp(), content); } } @SuppressLint("DefaultLocale") private void handleDeliveryReceipt(@NonNull SignalServiceContent content, - @NonNull SignalServiceReceiptMessage message) + @NonNull SignalServiceReceiptMessage message, + @NonNull Recipient senderRecipient) { - Recipient sender = Recipient.externalHighTrustPush(context, content.getSender()); - log(TAG, "Processing delivery receipts. Sender: " + sender.getId() + ", Device: " + content.getSenderDevice() + ", Timestamps: " + Util.join(message.getTimestamps(), ", ")); + log(TAG, "Processing delivery receipts. Sender: " + senderRecipient.getId() + ", Device: " + content.getSenderDevice() + ", Timestamps: " + Util.join(message.getTimestamps(), ", ")); List ids = Stream.of(message.getTimestamps()) - .map(t -> new SyncMessageId(sender.getId(), t)) + .map(t -> new SyncMessageId(senderRecipient.getId(), t)) .toList(); DatabaseFactory.getMmsSmsDatabase(context).incrementDeliveryReceiptCounts(ids, System.currentTimeMillis()); - DatabaseFactory.getMessageLogDatabase(context).deleteEntriesForRecipient(message.getTimestamps(), sender.getId(), content.getSenderDevice()); + DatabaseFactory.getMessageLogDatabase(context).deleteEntriesForRecipient(message.getTimestamps(), senderRecipient.getId(), content.getSenderDevice()); } @SuppressLint("DefaultLocale") private void handleReadReceipt(@NonNull SignalServiceContent content, - @NonNull SignalServiceReceiptMessage message) + @NonNull SignalServiceReceiptMessage message, + @NonNull Recipient senderRecipient) { if (!TextSecurePreferences.isReadReceiptsEnabled(context)) { log("Ignoring read receipts for IDs: " + Util.join(message.getTimestamps(), ", ")); return; } - Recipient sender = Recipient.externalHighTrustPush(context, content.getSender()); - log(TAG, "Processing read receipts. Sender: " + sender.getId() + ", Device: " + content.getSenderDevice() + ", Timestamps: " + Util.join(message.getTimestamps(), ", ")); + log(TAG, "Processing read receipts. Sender: " + senderRecipient.getId() + ", Device: " + content.getSenderDevice() + ", Timestamps: " + Util.join(message.getTimestamps(), ", ")); List ids = Stream.of(message.getTimestamps()) - .map(t -> new SyncMessageId(sender.getId(), t)) + .map(t -> new SyncMessageId(senderRecipient.getId(), t)) .toList(); Collection unhandled = DatabaseFactory.getMmsSmsDatabase(context).incrementReadReceiptCounts(ids, content.getTimestamp()); for (SyncMessageId id : unhandled) { - warn(String.valueOf(content.getTimestamp()), "[handleReadReceipt] Could not find matching message! timestamp: " + id.getTimetamp() + " author: " + sender.getId()); - ApplicationDependencies.getEarlyMessageCache().store(sender.getId(), id.getTimetamp(), content); + warn(String.valueOf(content.getTimestamp()), "[handleReadReceipt] Could not find matching message! timestamp: " + id.getTimetamp() + " author: " + senderRecipient.getId()); + ApplicationDependencies.getEarlyMessageCache().store(senderRecipient.getId(), id.getTimetamp(), content); } } private void handleTypingMessage(@NonNull SignalServiceContent content, - @NonNull SignalServiceTypingMessage typingMessage) + @NonNull SignalServiceTypingMessage typingMessage, + @NonNull Recipient senderRecipient) throws BadGroupIdException { if (!TextSecurePreferences.isTypingIndicatorsEnabled(context)) { return; } - Recipient author = Recipient.externalHighTrustPush(context, content.getSender()); - long threadId; if (typingMessage.getGroupId().isPresent()) { GroupId.Push groupId = GroupId.push(typingMessage.getGroupId().get()); - if (!DatabaseFactory.getGroupDatabase(context).isCurrentMember(groupId, author.getId())) { + if (!DatabaseFactory.getGroupDatabase(context).isCurrentMember(groupId, senderRecipient.getId())) { warn(String.valueOf(content.getTimestamp()), "Seen typing indicator for non-member"); return; } @@ -1750,7 +1759,7 @@ public final class MessageContentProcessor { threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient); } else { - threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(author); + threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(senderRecipient); } if (threadId <= 0) { @@ -1760,35 +1769,34 @@ public final class MessageContentProcessor { if (typingMessage.isTypingStarted()) { Log.d(TAG, "Typing started on thread " + threadId); - ApplicationDependencies.getTypingStatusRepository().onTypingStarted(context,threadId, author, content.getSenderDevice()); + ApplicationDependencies.getTypingStatusRepository().onTypingStarted(context,threadId, senderRecipient, content.getSenderDevice()); } else { Log.d(TAG, "Typing stopped on thread " + threadId); - ApplicationDependencies.getTypingStatusRepository().onTypingStopped(context, threadId, author, content.getSenderDevice(), false); + ApplicationDependencies.getTypingStatusRepository().onTypingStopped(context, threadId, senderRecipient, content.getSenderDevice(), false); } } - private void handleRetryReceipt(@NonNull SignalServiceContent content, @NonNull DecryptionErrorMessage decryptionErrorMessage) { + private void handleRetryReceipt(@NonNull SignalServiceContent content, @NonNull DecryptionErrorMessage decryptionErrorMessage, @NonNull Recipient senderRecipient) { if (!FeatureFlags.senderKey()) { warn(String.valueOf(content.getTimestamp()), "[RetryReceipt] Sender key not enabled, skipping retry receipt."); return; } - Recipient requester = Recipient.externalHighTrustPush(context, content.getSender()); - long sentTimestamp = decryptionErrorMessage.getTimestamp(); + long sentTimestamp = decryptionErrorMessage.getTimestamp(); - warn(content.getTimestamp(), "[RetryReceipt] Received a retry receipt from " + requester.getId() + ", device " + decryptionErrorMessage.getDeviceId() + " for message with timestamp " + sentTimestamp + "."); + warn(content.getTimestamp(), "[RetryReceipt] Received a retry receipt from " + senderRecipient.getId() + ", device " + decryptionErrorMessage.getDeviceId() + " for message with timestamp " + sentTimestamp + "."); - if (!requester.hasUuid()) { - warn(content.getTimestamp(), "[RetryReceipt] Requester " + requester.getId() + " somehow has no UUID! timestamp: " + sentTimestamp); + if (!senderRecipient.hasUuid()) { + warn(content.getTimestamp(), "[RetryReceipt] Requester " + senderRecipient.getId() + " somehow has no UUID! timestamp: " + sentTimestamp); return; } - MessageLogEntry messageLogEntry = DatabaseFactory.getMessageLogDatabase(context).getLogEntry(requester.getId(), content.getSenderDevice(), sentTimestamp); + MessageLogEntry messageLogEntry = DatabaseFactory.getMessageLogDatabase(context).getLogEntry(senderRecipient.getId(), content.getSenderDevice(), sentTimestamp); if (decryptionErrorMessage.getRatchetKey().isPresent()) { - handleIndividualRetryReceipt(requester, messageLogEntry, content, decryptionErrorMessage); + handleIndividualRetryReceipt(senderRecipient, messageLogEntry, content, decryptionErrorMessage); } else { - handleSenderKeyRetryReceipt(requester, messageLogEntry, content, decryptionErrorMessage); + handleSenderKeyRetryReceipt(senderRecipient, messageLogEntry, content, decryptionErrorMessage); } } @@ -2088,20 +2096,6 @@ public final class MessageContentProcessor { return getGroupRecipient(message != null ? message.getGroupContext() : Optional.absent()).or(() -> Recipient.externalHighTrustPush(context, content.getSender())); } - private Recipient getMessageDestination(@NonNull SignalServiceContent content, - @NonNull SignalServiceDataMessage message) - throws BadGroupIdException - { - return getGroupRecipient(message.getGroupContext()).or(() -> Recipient.externalHighTrustPush(context, content.getSender())); - } - - private Recipient getMessageDestination(@NonNull SignalServiceContent content, - @NonNull Optional groupContext) - throws BadGroupIdException - { - return getGroupRecipient(groupContext).or(() -> Recipient.externalPush(context, content.getSender())); - } - private Optional getGroupRecipient(Optional message) throws BadGroupIdException { @@ -2111,29 +2105,20 @@ public final class MessageContentProcessor { return Optional.absent(); } - private void notifyTypingStoppedFromIncomingMessage(@NonNull Recipient conversationRecipient, @NonNull SignalServiceAddress sender, int device) { - Recipient author = Recipient.externalPush(context, sender); - long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(conversationRecipient); + private void notifyTypingStoppedFromIncomingMessage(@NonNull Recipient senderRecipient, @NonNull Recipient conversationRecipient, int device) { + long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(conversationRecipient); if (threadId > 0 && TextSecurePreferences.isTypingIndicatorsEnabled(context)) { Log.d(TAG, "Typing stopped on thread " + threadId + " due to an incoming message."); - ApplicationDependencies.getTypingStatusRepository().onTypingStopped(context, threadId, author, device, true); + ApplicationDependencies.getTypingStatusRepository().onTypingStopped(context, threadId, senderRecipient, device, true); } } - private boolean shouldIgnore(@Nullable SignalServiceContent content) + private boolean shouldIgnore(@NonNull SignalServiceContent content, @NonNull Recipient sender, @NonNull Recipient conversation) throws BadGroupIdException { - if (content == null) { - warn("Got a message with null content."); - return true; - } - - Recipient sender = Recipient.externalHighTrustPush(context, content.getSender()); - if (content.getDataMessage().isPresent()) { - SignalServiceDataMessage message = content.getDataMessage().get(); - Recipient conversation = getMessageDestination(content, message); + SignalServiceDataMessage message = content.getDataMessage().get(); if (conversation.isGroup() && conversation.isBlocked()) { return true;