Search in sources :

Example 31 with GroupId

use of org.thoughtcrime.securesms.groups.GroupId in project Signal-Android by WhisperSystems.

the class MessageContentProcessor method updateGroupReceiptStatus.

private void updateGroupReceiptStatus(@NonNull SentTranscriptMessage message, long messageId, @NonNull GroupId groupString) {
    GroupReceiptDatabase receiptDatabase = SignalDatabase.groupReceipts();
    List<RecipientId> messageRecipientIds = Stream.of(message.getRecipients()).map(RecipientId::from).toList();
    List<Recipient> members = SignalDatabase.groups().getGroupMembers(groupString, GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF);
    Map<RecipientId, Integer> localReceipts = Stream.of(receiptDatabase.getGroupReceiptInfo(messageId)).collect(Collectors.toMap(GroupReceiptInfo::getRecipientId, GroupReceiptInfo::getStatus));
    for (RecipientId messageRecipientId : messageRecipientIds) {
        // noinspection ConstantConditions
        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());
        }
    }
    List<org.whispersystems.libsignal.util.Pair<RecipientId, Boolean>> unidentifiedStatus = Stream.of(members).map(m -> new org.whispersystems.libsignal.util.Pair<>(m.getId(), message.isUnidentified(m.requireServiceId().toString()))).toList();
    receiptDatabase.setUnidentified(unidentifiedStatus, messageId);
}
Also used : LinkPreview(org.thoughtcrime.securesms.linkpreview.LinkPreview) StickerPackOperationMessage(org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage) NonNull(androidx.annotation.NonNull) RecipientUtil(org.thoughtcrime.securesms.recipients.RecipientUtil) PaymentTransactionCheckJob(org.thoughtcrime.securesms.jobs.PaymentTransactionCheckJob) ProfileKey(org.signal.zkgroup.profiles.ProfileKey) LinkPreviewUtil(org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil) SecureRandom(java.security.SecureRandom) SignalServiceContent(org.whispersystems.signalservice.api.messages.SignalServiceContent) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) MmsMessageRecord(org.thoughtcrime.securesms.database.model.MmsMessageRecord) RequestGroupInfoJob(org.thoughtcrime.securesms.jobs.RequestGroupInfoJob) Map(java.util.Map) GroupChangeBusyException(org.thoughtcrime.securesms.groups.GroupChangeBusyException) ThreadRecord(org.thoughtcrime.securesms.database.model.ThreadRecord) OutgoingTextMessage(org.thoughtcrime.securesms.sms.OutgoingTextMessage) MultiDeviceGroupUpdateJob(org.thoughtcrime.securesms.jobs.MultiDeviceGroupUpdateJob) ApplicationDependencies(org.thoughtcrime.securesms.dependencies.ApplicationDependencies) SignalServiceAttachment(org.whispersystems.signalservice.api.messages.SignalServiceAttachment) ReactionRecord(org.thoughtcrime.securesms.database.model.ReactionRecord) GroupDatabase(org.thoughtcrime.securesms.database.GroupDatabase) ThreadDatabase(org.thoughtcrime.securesms.database.ThreadDatabase) Nullable(androidx.annotation.Nullable) SignalServiceGroupContext(org.whispersystems.signalservice.api.messages.SignalServiceGroupContext) StickerPackDownloadJob(org.thoughtcrime.securesms.jobs.StickerPackDownloadJob) SignalServiceGroupV2(org.whispersystems.signalservice.api.messages.SignalServiceGroupV2) MessageLogEntry(org.thoughtcrime.securesms.database.model.MessageLogEntry) CallId(org.signal.ringrtc.CallId) GroupUtil(org.thoughtcrime.securesms.util.GroupUtil) PendingRetryReceiptModel(org.thoughtcrime.securesms.database.model.PendingRetryReceiptModel) RefreshOwnProfileJob(org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob) Attachment(org.thoughtcrime.securesms.attachments.Attachment) MultiDeviceBlockedUpdateJob(org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob) OutgoingMediaMessage(org.thoughtcrime.securesms.mms.OutgoingMediaMessage) MediaUtil(org.thoughtcrime.securesms.util.MediaUtil) MmsSmsDatabase(org.thoughtcrime.securesms.database.MmsSmsDatabase) StickerDatabase(org.thoughtcrime.securesms.database.StickerDatabase) GroupsV1MigrationUtil(org.thoughtcrime.securesms.groups.GroupsV1MigrationUtil) MobileCoinPublicAddress(org.thoughtcrime.securesms.payments.MobileCoinPublicAddress) SignalDatabase(org.thoughtcrime.securesms.database.SignalDatabase) SignalServiceTypingMessage(org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage) ProfileKeySendJob(org.thoughtcrime.securesms.jobs.ProfileKeySendJob) Stream(com.annimon.stream.Stream) PaymentMetaDataUtil(org.thoughtcrime.securesms.database.PaymentMetaDataUtil) Util(org.thoughtcrime.securesms.util.Util) RefreshAttributesJob(org.thoughtcrime.securesms.jobs.RefreshAttributesJob) GroupRecord(org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord) AttachmentDatabase(org.thoughtcrime.securesms.database.AttachmentDatabase) RetrieveProfileJob(org.thoughtcrime.securesms.jobs.RetrieveProfileJob) ArrayList(java.util.ArrayList) PaymentDatabase(org.thoughtcrime.securesms.database.PaymentDatabase) BlockedListMessage(org.whispersystems.signalservice.api.messages.multidevice.BlockedListMessage) ContactModelMapper(org.thoughtcrime.securesms.contactshare.ContactModelMapper) MultiDeviceConfigurationUpdateJob(org.thoughtcrime.securesms.jobs.MultiDeviceConfigurationUpdateJob) NullMessageSendJob(org.thoughtcrime.securesms.jobs.NullMessageSendJob) IncomingEncryptedMessage(org.thoughtcrime.securesms.sms.IncomingEncryptedMessage) OutgoingEndSessionMessage(org.thoughtcrime.securesms.sms.OutgoingEndSessionMessage) HangupMessage(org.whispersystems.signalservice.api.messages.calls.HangupMessage) EmojiUtil(org.thoughtcrime.securesms.components.emoji.EmojiUtil) ECPublicKey(org.whispersystems.libsignal.ecc.ECPublicKey) SignalServiceGroup(org.whispersystems.signalservice.api.messages.SignalServiceGroup) SignalServiceCallMessage(org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage) ReadMessage(org.whispersystems.signalservice.api.messages.multidevice.ReadMessage) IncomingEndSessionMessage(org.thoughtcrime.securesms.sms.IncomingEndSessionMessage) ViewOnceOpenMessage(org.whispersystems.signalservice.api.messages.multidevice.ViewOnceOpenMessage) MessageRequestResponseMessage(org.whispersystems.signalservice.api.messages.multidevice.MessageRequestResponseMessage) OutgoingEncryptedMessage(org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage) KeysMessage(org.whispersystems.signalservice.api.messages.multidevice.KeysMessage) DistributionId(org.whispersystems.signalservice.api.push.DistributionId) GroupReceiptInfo(org.thoughtcrime.securesms.database.GroupReceiptDatabase.GroupReceiptInfo) RequestMessage(org.whispersystems.signalservice.api.messages.multidevice.RequestMessage) IdentityUtil(org.thoughtcrime.securesms.util.IdentityUtil) MessageId(org.thoughtcrime.securesms.database.model.MessageId) Collectors(com.annimon.stream.Collectors) GroupReceiptDatabase(org.thoughtcrime.securesms.database.GroupReceiptDatabase) Contact(org.thoughtcrime.securesms.contactshare.Contact) TextUtils(android.text.TextUtils) Hex(org.thoughtcrime.securesms.util.Hex) IOException(java.io.IOException) Optional(org.whispersystems.libsignal.util.guava.Optional) StickerLocator(org.thoughtcrime.securesms.stickers.StickerLocator) GroupV1MessageProcessor(org.thoughtcrime.securesms.groups.GroupV1MessageProcessor) TrimThreadJob(org.thoughtcrime.securesms.jobs.TrimThreadJob) IncomingMediaMessage(org.thoughtcrime.securesms.mms.IncomingMediaMessage) Money(org.whispersystems.signalservice.api.payments.Money) SignalStore(org.thoughtcrime.securesms.keyvalue.SignalStore) VerifiedMessage(org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage) MessageNotifier(org.thoughtcrime.securesms.notifications.MessageNotifier) SignalServiceDataMessage(org.whispersystems.signalservice.api.messages.SignalServiceDataMessage) SlideDeck(org.thoughtcrime.securesms.mms.SlideDeck) AttachmentDownloadJob(org.thoughtcrime.securesms.jobs.AttachmentDownloadJob) SerializationException(com.mobilecoin.lib.exceptions.SerializationException) PointerAttachment(org.thoughtcrime.securesms.attachments.PointerAttachment) JobManager(org.thoughtcrime.securesms.jobmanager.JobManager) MultiDeviceStickerPackSyncJob(org.thoughtcrime.securesms.jobs.MultiDeviceStickerPackSyncJob) WebRtcData(org.thoughtcrime.securesms.service.webrtc.WebRtcData) SentTranscriptMessage(org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage) Mention(org.thoughtcrime.securesms.database.model.Mention) MessageRecord(org.thoughtcrime.securesms.database.model.MessageRecord) SignalServiceAddress(org.whispersystems.signalservice.api.push.SignalServiceAddress) AutomaticSessionResetJob(org.thoughtcrime.securesms.jobs.AutomaticSessionResetJob) SecurityEvent(org.thoughtcrime.securesms.crypto.SecurityEvent) StorageSyncHelper(org.thoughtcrime.securesms.storage.StorageSyncHelper) Locale(java.util.Locale) ResendMessageJob(org.thoughtcrime.securesms.jobs.ResendMessageJob) SignalProtocolAddress(org.whispersystems.libsignal.SignalProtocolAddress) Recipient(org.thoughtcrime.securesms.recipients.Recipient) BusyMessage(org.whispersystems.signalservice.api.messages.calls.BusyMessage) StickerSlide(org.thoughtcrime.securesms.mms.StickerSlide) MultiDeviceContactSyncJob(org.thoughtcrime.securesms.jobs.MultiDeviceContactSyncJob) SyncMessageId(org.thoughtcrime.securesms.database.MessageDatabase.SyncMessageId) PaymentLedgerUpdateJob(org.thoughtcrime.securesms.jobs.PaymentLedgerUpdateJob) Collection(java.util.Collection) ProfileKeyUtil(org.thoughtcrime.securesms.crypto.ProfileKeyUtil) SendDeliveryReceiptJob(org.thoughtcrime.securesms.jobs.SendDeliveryReceiptJob) OutgoingSecureMediaMessage(org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage) UUID(java.util.UUID) SenderKeyDistributionSendJob(org.thoughtcrime.securesms.jobs.SenderKeyDistributionSendJob) OutgoingExpirationUpdateMessage(org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage) Objects(java.util.Objects) Log(org.signal.core.util.logging.Log) FeatureFlags(org.thoughtcrime.securesms.util.FeatureFlags) List(java.util.List) MarkReadReceiver(org.thoughtcrime.securesms.notifications.MarkReadReceiver) ViewedMessage(org.whispersystems.signalservice.api.messages.multidevice.ViewedMessage) GroupNotAMemberException(org.thoughtcrime.securesms.groups.GroupNotAMemberException) GroupId(org.thoughtcrime.securesms.groups.GroupId) SharedContact(org.whispersystems.signalservice.api.messages.shared.SharedContact) MessageDatabase(org.thoughtcrime.securesms.database.MessageDatabase) ContactsMessage(org.whispersystems.signalservice.api.messages.multidevice.ContactsMessage) GroupV2UpdateSelfProfileKeyJob(org.thoughtcrime.securesms.jobs.GroupV2UpdateSelfProfileKeyJob) IncomingTextMessage(org.thoughtcrime.securesms.sms.IncomingTextMessage) SignalServiceReceiptMessage(org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage) InsertResult(org.thoughtcrime.securesms.database.MessageDatabase.InsertResult) PushProcessMessageJob(org.thoughtcrime.securesms.jobs.PushProcessMessageJob) AnswerMessage(org.whispersystems.signalservice.api.messages.calls.AnswerMessage) MultiDevicePniIdentityUpdateJob(org.thoughtcrime.securesms.jobs.MultiDevicePniIdentityUpdateJob) Context(android.content.Context) ConfigurationMessage(org.whispersystems.signalservice.api.messages.multidevice.ConfigurationMessage) RemotePeer(org.thoughtcrime.securesms.ringrtc.RemotePeer) BadGroupIdException(org.thoughtcrime.securesms.groups.BadGroupIdException) HashMap(java.util.HashMap) RecipientDatabase(org.thoughtcrime.securesms.database.RecipientDatabase) OfferMessage(org.whispersystems.signalservice.api.messages.calls.OfferMessage) DatabaseAttachment(org.thoughtcrime.securesms.attachments.DatabaseAttachment) UriAttachment(org.thoughtcrime.securesms.attachments.UriAttachment) TextSecurePreferences(org.thoughtcrime.securesms.util.TextSecurePreferences) OpaqueMessage(org.whispersystems.signalservice.api.messages.calls.OpaqueMessage) GroupManager(org.thoughtcrime.securesms.groups.GroupManager) SuppressLint(android.annotation.SuppressLint) GroupCallPeekJob(org.thoughtcrime.securesms.jobs.GroupCallPeekJob) QuoteModel(org.thoughtcrime.securesms.mms.QuoteModel) Build(android.os.Build) LinkedList(java.util.LinkedList) MultiDeviceContactUpdateJob(org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob) MultiDeviceKeysUpdateJob(org.thoughtcrime.securesms.jobs.MultiDeviceKeysUpdateJob) SignalServiceAttachmentPointer(org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer) DecryptionErrorMessage(org.whispersystems.libsignal.protocol.DecryptionErrorMessage) StickerRecord(org.thoughtcrime.securesms.database.model.StickerRecord) MmsException(org.thoughtcrime.securesms.mms.MmsException) RemoteDeleteUtil(org.thoughtcrime.securesms.util.RemoteDeleteUtil) TombstoneAttachment(org.thoughtcrime.securesms.attachments.TombstoneAttachment) OutgoingPaymentMessage(org.whispersystems.signalservice.api.messages.multidevice.OutgoingPaymentMessage) TimeUnit(java.util.concurrent.TimeUnit) IceUpdateMessage(org.whispersystems.signalservice.api.messages.calls.IceUpdateMessage) RateLimitUtil(org.thoughtcrime.securesms.ratelimit.RateLimitUtil) SignalServiceSyncMessage(org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage) SessionRecord(org.whispersystems.libsignal.state.SessionRecord) Collections(java.util.Collections) GroupReceiptDatabase(org.thoughtcrime.securesms.database.GroupReceiptDatabase) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) Recipient(org.thoughtcrime.securesms.recipients.Recipient)

Example 32 with GroupId

use of org.thoughtcrime.securesms.groups.GroupId in project Signal-Android by WhisperSystems.

the class MessageContentProcessor method handleSenderKeyRetryReceipt.

private void handleSenderKeyRetryReceipt(@NonNull Recipient requester, @Nullable MessageLogEntry messageLogEntry, @NonNull SignalServiceContent content, @NonNull DecryptionErrorMessage decryptionErrorMessage) {
    long sentTimestamp = decryptionErrorMessage.getTimestamp();
    MessageRecord relatedMessage = findRetryReceiptRelatedMessage(context, messageLogEntry, sentTimestamp);
    if (relatedMessage == null) {
        warn(content.getTimestamp(), "[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;
    }
    Recipient threadRecipient = SignalDatabase.threads().getRecipientForThreadId(relatedMessage.getThreadId());
    if (threadRecipient == null) {
        warn(content.getTimestamp(), "[RetryReceipt-SK] Could not find a thread recipient! Skipping.");
        return;
    }
    if (!threadRecipient.isPushV2Group()) {
        warn(content.getTimestamp(), "[RetryReceipt-SK] Thread recipient is not a v2 group! Skipping.");
        return;
    }
    GroupId.V2 groupId = threadRecipient.requireGroupId().requireV2();
    DistributionId distributionId = SignalDatabase.groups().getOrCreateDistributionId(groupId);
    SignalProtocolAddress requesterAddress = new SignalProtocolAddress(requester.requireServiceId().toString(), content.getSenderDevice());
    SignalDatabase.senderKeyShared().delete(distributionId, Collections.singleton(requesterAddress));
    if (messageLogEntry != null) {
        warn(content.getTimestamp(), "[RetryReceipt-SK] Found MSL entry for " + requester.getId() + " (" + requesterAddress + ") with timestamp " + sentTimestamp + ". Scheduling a resend.");
        ApplicationDependencies.getJobManager().add(new ResendMessageJob(messageLogEntry.getRecipientId(), messageLogEntry.getDateSent(), messageLogEntry.getContent(), messageLogEntry.getContentHint(), groupId, distributionId));
    } else {
        warn(content.getTimestamp(), "[RetryReceipt-SK] Unable to find MSL entry for " + requester.getId() + " (" + requesterAddress + ") with timestamp " + sentTimestamp + ".");
        Optional<GroupRecord> groupRecord = SignalDatabase.groups().getGroup(groupId);
        if (!groupRecord.isPresent()) {
            warn(content.getTimestamp(), "[RetryReceipt-SK] Could not find a record for the group!");
            return;
        }
        if (!groupRecord.get().getMembers().contains(requester.getId())) {
            warn(content.getTimestamp(), "[RetryReceipt-SK] The requester is not in the group, so we cannot send them a SenderKeyDistributionMessage.");
            return;
        }
        warn(content.getTimestamp(), "[RetryReceipt-SK] The requester is in the group, so we'll send them a SenderKeyDistributionMessage.");
        ApplicationDependencies.getJobManager().add(new SenderKeyDistributionSendJob(requester.getId(), groupRecord.get().getId().requireV2()));
    }
}
Also used : SenderKeyDistributionSendJob(org.thoughtcrime.securesms.jobs.SenderKeyDistributionSendJob) ResendMessageJob(org.thoughtcrime.securesms.jobs.ResendMessageJob) MmsMessageRecord(org.thoughtcrime.securesms.database.model.MmsMessageRecord) MessageRecord(org.thoughtcrime.securesms.database.model.MessageRecord) Recipient(org.thoughtcrime.securesms.recipients.Recipient) DistributionId(org.whispersystems.signalservice.api.push.DistributionId) GroupRecord(org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord) SignalProtocolAddress(org.whispersystems.libsignal.SignalProtocolAddress) GroupId(org.thoughtcrime.securesms.groups.GroupId)

Example 33 with GroupId

use of org.thoughtcrime.securesms.groups.GroupId in project Signal-Android by WhisperSystems.

the class MessageContentProcessor method handleMessage.

private void handleMessage(@NonNull SignalServiceContent content, long timestamp, @NonNull Recipient senderRecipient, @NonNull Optional<Long> smsMessageId) throws IOException, GroupChangeBusyException {
    try {
        Recipient threadRecipient = getMessageDestination(content);
        if (shouldIgnore(content, senderRecipient, threadRecipient)) {
            log(content.getTimestamp(), "Ignoring message.");
            return;
        }
        PendingRetryReceiptModel pending = ApplicationDependencies.getPendingRetryReceiptCache().get(senderRecipient.getId(), content.getTimestamp());
        long receivedTime = handlePendingRetry(pending, content, threadRecipient);
        log(String.valueOf(content.getTimestamp()), "Beginning message processing. Sender: " + formatSender(senderRecipient, content));
        if (content.getDataMessage().isPresent()) {
            GroupDatabase groupDatabase = SignalDatabase.groups();
            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> 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(), senderRecipient)) {
                    return;
                }
            }
            MessageId messageId = null;
            if (isInvalidMessage(message))
                handleInvalidMessage(content.getSender(), content.getSenderDevice(), groupId, content.getTimestamp(), smsMessageId);
            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 (message.getStoryContext().isPresent())
                handleStoryMessage(content);
            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(), senderRecipient);
            }
            if (message.getProfileKey().isPresent()) {
                handleProfileKey(content, message.getProfileKey().get(), senderRecipient);
            }
            if (content.isNeedsReceipt() && messageId != null) {
                handleNeedsDeliveryReceipt(content, message, messageId);
            } else if (!content.isNeedsReceipt()) {
                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 (!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, SignalDatabase.threads().getOrCreateThreadIdFor(threadRecipient), true)).enqueue();
                    }
                }
            }
        } else if (content.getSyncMessage().isPresent()) {
            TextSecurePreferences.setMultiDevice(context, true);
            SignalServiceSyncMessage syncMessage = content.getSyncMessage().get();
            if (syncMessage.getSent().isPresent())
                handleSynchronizeSentMessage(content, syncMessage.getSent().get(), senderRecipient);
            else if (syncMessage.getRequest().isPresent())
                handleSynchronizeRequestMessage(syncMessage.getRequest().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());
            else if (syncMessage.getStickerPackOperations().isPresent())
                handleSynchronizeStickerPackOperation(syncMessage.getStickerPackOperations().get(), content.getTimestamp());
            else if (syncMessage.getConfiguration().isPresent())
                handleSynchronizeConfigurationMessage(syncMessage.getConfiguration().get(), content.getTimestamp());
            else if (syncMessage.getBlockedList().isPresent())
                handleSynchronizeBlockedListMessage(syncMessage.getBlockedList().get());
            else if (syncMessage.getFetchType().isPresent())
                handleSynchronizeFetchMessage(syncMessage.getFetchType().get(), content.getTimestamp());
            else if (syncMessage.getMessageRequestResponse().isPresent())
                handleSynchronizeMessageRequestResponse(syncMessage.getMessageRequestResponse().get(), content.getTimestamp());
            else if (syncMessage.getOutgoingPaymentMessage().isPresent())
                handleSynchronizeOutgoingPayment(content, syncMessage.getOutgoingPaymentMessage().get());
            else if (syncMessage.getKeys().isPresent())
                handleSynchronizeKeys(syncMessage.getKeys().get(), content.getTimestamp());
            else if (syncMessage.getContacts().isPresent())
                handleSynchronizeContacts(syncMessage.getContacts().get(), content.getTimestamp());
            else
                warn(String.valueOf(content.getTimestamp()), "Contains no known sync types...");
        } else if (content.getCallMessage().isPresent()) {
            log(String.valueOf(content.getTimestamp()), "Got call message...");
            SignalServiceCallMessage message = content.getCallMessage().get();
            Optional<Integer> destinationDeviceId = message.getDestinationDeviceId();
            if (destinationDeviceId.isPresent() && destinationDeviceId.get() != SignalStore.account().getDeviceId()) {
                log(String.valueOf(content.getTimestamp()), String.format(Locale.US, "Ignoring call message that is not for this device! intended: %d, this: %d", destinationDeviceId.get(), SignalStore.account().getDeviceId()));
                return;
            }
            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, 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(), senderRecipient);
        } else if (content.getDecryptionErrorMessage().isPresent()) {
            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(senderRecipient);
        if (pending != null) {
            warn(content.getTimestamp(), "Pending retry was processed. Deleting.");
            ApplicationDependencies.getPendingRetryReceiptCache().delete(pending);
        }
    } catch (StorageFailedException e) {
        warn(String.valueOf(content.getTimestamp()), e);
        handleCorruptMessage(e.getSender(), e.getSenderDevice(), timestamp, smsMessageId);
    } catch (BadGroupIdException e) {
        warn(String.valueOf(content.getTimestamp()), "Ignoring message with bad group id", e);
    }
}
Also used : PendingRetryReceiptModel(org.thoughtcrime.securesms.database.model.PendingRetryReceiptModel) SignalServiceReceiptMessage(org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage) Recipient(org.thoughtcrime.securesms.recipients.Recipient) SignalServiceSyncMessage(org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage) GroupId(org.thoughtcrime.securesms.groups.GroupId) SignalServiceDataMessage(org.whispersystems.signalservice.api.messages.SignalServiceDataMessage) RefreshAttributesJob(org.thoughtcrime.securesms.jobs.RefreshAttributesJob) GroupDatabase(org.thoughtcrime.securesms.database.GroupDatabase) SignalServiceCallMessage(org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage) BadGroupIdException(org.thoughtcrime.securesms.groups.BadGroupIdException) MessageId(org.thoughtcrime.securesms.database.model.MessageId) SyncMessageId(org.thoughtcrime.securesms.database.MessageDatabase.SyncMessageId)

Example 34 with GroupId

use of org.thoughtcrime.securesms.groups.GroupId in project Signal-Android by WhisperSystems.

the class MessageDecryptionUtil method handleRetry.

@NonNull
private static Job handleRetry(@NonNull Context context, @NonNull Recipient sender, @NonNull SignalServiceEnvelope envelope, @NonNull ProtocolException protocolException) {
    ContentHint contentHint = ContentHint.fromType(protocolException.getContentHint());
    int senderDevice = protocolException.getSenderDevice();
    long receivedTimestamp = System.currentTimeMillis();
    Optional<GroupId> groupId = Optional.absent();
    if (protocolException.getGroupId().isPresent()) {
        try {
            groupId = Optional.of(GroupId.push(protocolException.getGroupId().get()));
        } catch (BadGroupIdException e) {
            Log.w(TAG, "[" + envelope.getTimestamp() + "] Bad groupId!");
        }
    }
    Log.w(TAG, "[" + envelope.getTimestamp() + "] Could not decrypt a message with a type of " + contentHint);
    long threadId;
    if (groupId.isPresent()) {
        Recipient groupRecipient = Recipient.externalPossiblyMigratedGroup(context, groupId.get());
        threadId = SignalDatabase.threads().getOrCreateThreadIdFor(groupRecipient);
    } else {
        threadId = SignalDatabase.threads().getOrCreateThreadIdFor(sender);
    }
    switch(contentHint) {
        case DEFAULT:
            Log.w(TAG, "[" + envelope.getTimestamp() + "] Inserting an error right away because it's " + contentHint);
            SignalDatabase.sms().insertBadDecryptMessage(sender.getId(), senderDevice, envelope.getTimestamp(), receivedTimestamp, threadId);
            break;
        case RESENDABLE:
            Log.w(TAG, "[" + envelope.getTimestamp() + "] Inserting into pending retries store because it's " + contentHint);
            ApplicationDependencies.getPendingRetryReceiptCache().insert(sender.getId(), senderDevice, envelope.getTimestamp(), receivedTimestamp, threadId);
            ApplicationDependencies.getPendingRetryReceiptManager().scheduleIfNecessary();
            break;
        case IMPLICIT:
            Log.w(TAG, "[" + envelope.getTimestamp() + "] Not inserting any error because it's " + contentHint);
            break;
    }
    byte[] originalContent;
    int envelopeType;
    if (protocolException.getUnidentifiedSenderMessageContent().isPresent()) {
        originalContent = protocolException.getUnidentifiedSenderMessageContent().get().getContent();
        envelopeType = protocolException.getUnidentifiedSenderMessageContent().get().getType();
    } else {
        originalContent = envelope.getContent();
        envelopeType = envelopeTypeToCiphertextMessageType(envelope.getType());
    }
    DecryptionErrorMessage decryptionErrorMessage = DecryptionErrorMessage.forOriginalMessage(originalContent, envelopeType, envelope.getTimestamp(), senderDevice);
    return new SendRetryReceiptJob(sender.getId(), groupId, decryptionErrorMessage);
}
Also used : DecryptionErrorMessage(org.whispersystems.libsignal.protocol.DecryptionErrorMessage) ContentHint(org.whispersystems.signalservice.api.crypto.ContentHint) SendRetryReceiptJob(org.thoughtcrime.securesms.jobs.SendRetryReceiptJob) Recipient(org.thoughtcrime.securesms.recipients.Recipient) BadGroupIdException(org.thoughtcrime.securesms.groups.BadGroupIdException) ContentHint(org.whispersystems.signalservice.api.crypto.ContentHint) GroupId(org.thoughtcrime.securesms.groups.GroupId) NonNull(androidx.annotation.NonNull)

Example 35 with GroupId

use of org.thoughtcrime.securesms.groups.GroupId in project Signal-Android by WhisperSystems.

the class SenderKeyDistributionSendJob method onRun.

@Override
protected void onRun() throws Exception {
    GroupDatabase groupDatabase = SignalDatabase.groups();
    if (!groupDatabase.isCurrentMember(groupId, recipientId)) {
        Log.w(TAG, recipientId + " is no longer a member of " + groupId + "! Not sending.");
        return;
    }
    Recipient recipient = Recipient.resolved(recipientId);
    if (recipient.getSenderKeyCapability() != Recipient.Capability.SUPPORTED) {
        Log.w(TAG, recipientId + " does not support sender key! Not sending.");
        return;
    }
    if (recipient.isUnregistered()) {
        Log.w(TAG, recipient.getId() + " not registered!");
        return;
    }
    SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
    List<SignalServiceAddress> address = Collections.singletonList(RecipientUtil.toSignalServiceAddress(context, recipient));
    DistributionId distributionId = groupDatabase.getOrCreateDistributionId(groupId);
    SenderKeyDistributionMessage message = messageSender.getOrCreateNewGroupSession(distributionId);
    List<Optional<UnidentifiedAccessPair>> access = UnidentifiedAccessUtil.getAccessFor(context, Collections.singletonList(recipient));
    SendMessageResult result = messageSender.sendSenderKeyDistributionMessage(distributionId, address, access, message, groupId.getDecodedId()).get(0);
    if (result.isSuccess()) {
        List<SignalProtocolAddress> addresses = result.getSuccess().getDevices().stream().map(device -> recipient.requireServiceId().toProtocolAddress(device)).collect(Collectors.toList());
        ApplicationDependencies.getProtocolStore().aci().markSenderKeySharedWith(distributionId, addresses);
    }
}
Also used : SignalDatabase(org.thoughtcrime.securesms.database.SignalDatabase) SendMessageResult(org.whispersystems.signalservice.api.messages.SendMessageResult) NonNull(androidx.annotation.NonNull) Data(org.thoughtcrime.securesms.jobmanager.Data) RecipientUtil(org.thoughtcrime.securesms.recipients.RecipientUtil) SignalServiceAddress(org.whispersystems.signalservice.api.push.SignalServiceAddress) UnidentifiedAccessPair(org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) SignalProtocolAddress(org.whispersystems.libsignal.SignalProtocolAddress) Recipient(org.thoughtcrime.securesms.recipients.Recipient) DistributionId(org.whispersystems.signalservice.api.push.DistributionId) SignalServiceMessageSender(org.whispersystems.signalservice.api.SignalServiceMessageSender) ApplicationDependencies(org.thoughtcrime.securesms.dependencies.ApplicationDependencies) SenderKeyDistributionMessage(org.whispersystems.libsignal.protocol.SenderKeyDistributionMessage) NetworkConstraint(org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint) UnidentifiedAccessUtil(org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil) GroupDatabase(org.thoughtcrime.securesms.database.GroupDatabase) Collectors(java.util.stream.Collectors) Optional(org.whispersystems.libsignal.util.guava.Optional) TimeUnit(java.util.concurrent.TimeUnit) Log(org.signal.core.util.logging.Log) List(java.util.List) GroupId(org.thoughtcrime.securesms.groups.GroupId) Job(org.thoughtcrime.securesms.jobmanager.Job) Collections(java.util.Collections) Optional(org.whispersystems.libsignal.util.guava.Optional) SignalServiceMessageSender(org.whispersystems.signalservice.api.SignalServiceMessageSender) Recipient(org.thoughtcrime.securesms.recipients.Recipient) DistributionId(org.whispersystems.signalservice.api.push.DistributionId) SendMessageResult(org.whispersystems.signalservice.api.messages.SendMessageResult) SenderKeyDistributionMessage(org.whispersystems.libsignal.protocol.SenderKeyDistributionMessage) GroupDatabase(org.thoughtcrime.securesms.database.GroupDatabase) SignalServiceAddress(org.whispersystems.signalservice.api.push.SignalServiceAddress) SignalProtocolAddress(org.whispersystems.libsignal.SignalProtocolAddress)

Aggregations

GroupId (org.thoughtcrime.securesms.groups.GroupId)41 Recipient (org.thoughtcrime.securesms.recipients.Recipient)26 NonNull (androidx.annotation.NonNull)22 RecipientId (org.thoughtcrime.securesms.recipients.RecipientId)13 Context (android.content.Context)12 List (java.util.List)11 Log (org.signal.core.util.logging.Log)11 GroupDatabase (org.thoughtcrime.securesms.database.GroupDatabase)11 Collections (java.util.Collections)10 SignalDatabase (org.thoughtcrime.securesms.database.SignalDatabase)10 ApplicationDependencies (org.thoughtcrime.securesms.dependencies.ApplicationDependencies)10 Optional (org.whispersystems.libsignal.util.guava.Optional)10 Nullable (androidx.annotation.Nullable)9 IOException (java.io.IOException)9 LinkedList (java.util.LinkedList)8 Collectors (java.util.stream.Collectors)8 SignalStore (org.thoughtcrime.securesms.keyvalue.SignalStore)8 SendMessageResult (org.whispersystems.signalservice.api.messages.SendMessageResult)8 Intent (android.content.Intent)7 Stream (com.annimon.stream.Stream)7