Search in sources :

Example 26 with GroupId

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

the class PushProcessMessageJob method createParameters.

@WorkerThread
@NonNull
private static Parameters createParameters(@Nullable SignalServiceContent content, @Nullable ExceptionMetadata exceptionMetadata) {
    Context context = ApplicationDependencies.getApplication();
    String queueName = QUEUE_PREFIX;
    Parameters.Builder builder = new Parameters.Builder().setMaxAttempts(Parameters.UNLIMITED);
    if (content != null) {
        SignalServiceGroupContext signalServiceGroupContext = GroupUtil.getGroupContextIfPresent(content);
        if (signalServiceGroupContext != null) {
            try {
                GroupId groupId = GroupUtil.idFromGroupContext(signalServiceGroupContext);
                queueName = getQueueName(Recipient.externalPossiblyMigratedGroup(context, groupId).getId());
                if (groupId.isV2()) {
                    int localRevision = SignalDatabase.groups().getGroupV2Revision(groupId.requireV2());
                    if (signalServiceGroupContext.getGroupV2().get().getRevision() > localRevision || SignalDatabase.groups().getGroupV1ByExpectedV2(groupId.requireV2()).isPresent()) {
                        Log.i(TAG, "Adding network constraint to group-related job.");
                        builder.addConstraint(NetworkConstraint.KEY).setLifespan(TimeUnit.DAYS.toMillis(30));
                    }
                }
            } catch (BadGroupIdException e) {
                Log.w(TAG, "Bad groupId! Using default queue. ID: " + content.getTimestamp());
            }
        } else if (content.getSyncMessage().isPresent() && content.getSyncMessage().get().getSent().isPresent() && content.getSyncMessage().get().getSent().get().getDestination().isPresent()) {
            queueName = getQueueName(RecipientId.fromHighTrust(content.getSyncMessage().get().getSent().get().getDestination().get()));
        } else {
            queueName = getQueueName(RecipientId.fromHighTrust(content.getSender()));
        }
    } else if (exceptionMetadata != null) {
        Recipient recipient = exceptionMetadata.getGroupId() != null ? Recipient.externalPossiblyMigratedGroup(context, exceptionMetadata.getGroupId()) : Recipient.external(context, exceptionMetadata.getSender());
        queueName = getQueueName(recipient.getId());
    }
    builder.setQueue(queueName);
    return builder.build();
}
Also used : Context(android.content.Context) SignalServiceGroupContext(org.whispersystems.signalservice.api.messages.SignalServiceGroupContext) Recipient(org.thoughtcrime.securesms.recipients.Recipient) BadGroupIdException(org.thoughtcrime.securesms.groups.BadGroupIdException) SignalServiceGroupContext(org.whispersystems.signalservice.api.messages.SignalServiceGroupContext) NetworkConstraint(org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint) GroupId(org.thoughtcrime.securesms.groups.GroupId) WorkerThread(androidx.annotation.WorkerThread) NonNull(androidx.annotation.NonNull)

Example 27 with GroupId

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

the class SignalCallManager method onSendCallMessageToGroup.

@Override
public void onSendCallMessageToGroup(@NonNull byte[] groupIdBytes, @NonNull byte[] message, @NonNull CallManager.CallMessageUrgency urgency) {
    Log.i(TAG, "onSendCallMessageToGroup():");
    networkExecutor.execute(() -> {
        try {
            GroupId groupId = GroupId.v2(new GroupIdentifier(groupIdBytes));
            List<Recipient> recipients = SignalDatabase.groups().getGroupMembers(groupId, GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF);
            recipients = RecipientUtil.getEligibleForSending((recipients.stream().map(Recipient::resolve).filter(r -> !r.isBlocked()).collect(Collectors.toList())));
            OpaqueMessage opaqueMessage = new OpaqueMessage(message, getUrgencyFromCallUrgency(urgency));
            SignalServiceCallMessage callMessage = SignalServiceCallMessage.forOutgoingGroupOpaque(groupId.getDecodedId(), System.currentTimeMillis(), opaqueMessage, true, null);
            RecipientAccessList accessList = new RecipientAccessList(recipients);
            List<SendMessageResult> results = GroupSendUtil.sendCallMessage(context, groupId.requireV2(), recipients, callMessage);
            Set<RecipientId> identifyFailureRecipientIds = results.stream().filter(result -> result.getIdentityFailure() != null).map(result -> accessList.requireIdByAddress(result.getAddress())).collect(Collectors.toSet());
            if (Util.hasItems(identifyFailureRecipientIds)) {
                process((s, p) -> p.handleGroupMessageSentError(s, identifyFailureRecipientIds, UNTRUSTED_IDENTITY));
                RetrieveProfileJob.enqueue(identifyFailureRecipientIds);
            }
        } catch (UntrustedIdentityException | IOException | InvalidInputException e) {
            Log.w(TAG, "onSendCallMessageToGroup failed", e);
        }
    });
}
Also used : SignalStore(org.thoughtcrime.securesms.keyvalue.SignalStore) SignalAudioManager(org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager) SignalServiceAccountManager(org.whispersystems.signalservice.api.SignalServiceAccountManager) NetworkRoute(org.signal.ringrtc.NetworkRoute) BubbleUtil(org.thoughtcrime.securesms.util.BubbleUtil) SendMessageResult(org.whispersystems.signalservice.api.messages.SendMessageResult) CallingResponse(org.whispersystems.signalservice.api.messages.calls.CallingResponse) TurnServerInfo(org.whispersystems.signalservice.api.messages.calls.TurnServerInfo) NonNull(androidx.annotation.NonNull) RecipientUtil(org.thoughtcrime.securesms.recipients.RecipientUtil) CallException(org.signal.ringrtc.CallException) WebRtcCallActivity(org.thoughtcrime.securesms.WebRtcCallActivity) CallManager(org.signal.ringrtc.CallManager) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) NetworkUtil(org.thoughtcrime.securesms.util.NetworkUtil) Recipient(org.thoughtcrime.securesms.recipients.Recipient) IDLE(org.thoughtcrime.securesms.events.WebRtcViewModel.GroupCallState.IDLE) SignalExecutors(org.signal.core.util.concurrent.SignalExecutors) WebRtcUtil.getUrgencyFromCallUrgency(org.thoughtcrime.securesms.service.webrtc.WebRtcUtil.getUrgencyFromCallUrgency) GroupExternalCredential(org.signal.storageservice.protos.groups.GroupExternalCredential) ACI(org.whispersystems.signalservice.api.push.ACI) HttpHeader(org.signal.ringrtc.HttpHeader) ApplicationDependencies(org.thoughtcrime.securesms.dependencies.ApplicationDependencies) Collection(java.util.Collection) GroupCallUpdateSendJob(org.thoughtcrime.securesms.jobs.GroupCallUpdateSendJob) Set(java.util.Set) UnidentifiedAccessUtil(org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil) UUID(java.util.UUID) GroupDatabase(org.thoughtcrime.securesms.database.GroupDatabase) UNTRUSTED_IDENTITY(org.thoughtcrime.securesms.events.WebRtcViewModel.State.UNTRUSTED_IDENTITY) Collectors(java.util.stream.Collectors) Executors(java.util.concurrent.Executors) InvalidInputException(org.signal.zkgroup.InvalidInputException) GroupCall(org.signal.ringrtc.GroupCall) Log(org.signal.core.util.logging.Log) List(java.util.List) Nullable(androidx.annotation.Nullable) Application(android.app.Application) GroupId(org.thoughtcrime.securesms.groups.GroupId) CallId(org.signal.ringrtc.CallId) CameraEventListener(org.thoughtcrime.securesms.ringrtc.CameraEventListener) Context(android.content.Context) RecipientAccessList(org.thoughtcrime.securesms.util.RecipientAccessList) SignalDatabase(org.thoughtcrime.securesms.database.SignalDatabase) RemotePeer(org.thoughtcrime.securesms.ringrtc.RemotePeer) Stream(com.annimon.stream.Stream) Remote(org.signal.ringrtc.Remote) Util(org.thoughtcrime.securesms.util.Util) VerificationFailedException(org.signal.zkgroup.VerificationFailedException) Intent(android.content.Intent) AppForegroundObserver(org.thoughtcrime.securesms.util.AppForegroundObserver) RetrieveProfileJob(org.thoughtcrime.securesms.jobs.RetrieveProfileJob) NETWORK_FAILURE(org.thoughtcrime.securesms.events.WebRtcViewModel.State.NETWORK_FAILURE) OfferMessage(org.whispersystems.signalservice.api.messages.calls.OfferMessage) LockManager(org.thoughtcrime.securesms.webrtc.locks.LockManager) TextSecurePreferences(org.thoughtcrime.securesms.util.TextSecurePreferences) OpaqueMessage(org.whispersystems.signalservice.api.messages.calls.OpaqueMessage) GroupManager(org.thoughtcrime.securesms.groups.GroupManager) CameraState(org.thoughtcrime.securesms.ringrtc.CameraState) Pair(org.whispersystems.libsignal.util.Pair) EventBus(org.greenrobot.eventbus.EventBus) SignalServiceCallMessage(org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage) Build(android.os.Build) LinkedList(java.util.LinkedList) GroupSendUtil(org.thoughtcrime.securesms.messages.GroupSendUtil) WebRtcServiceState(org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState) ExecutorService(java.util.concurrent.ExecutorService) SignalServiceMessageSender(org.whispersystems.signalservice.api.SignalServiceMessageSender) PeerConnection(org.webrtc.PeerConnection) Executor(java.util.concurrent.Executor) WebRtcViewModel(org.thoughtcrime.securesms.events.WebRtcViewModel) IOException(java.io.IOException) NO_SUCH_USER(org.thoughtcrime.securesms.events.WebRtcViewModel.State.NO_SUCH_USER) GroupCallPeekEvent(org.thoughtcrime.securesms.events.GroupCallPeekEvent) Optional(org.whispersystems.libsignal.util.guava.Optional) UnregisteredUserException(org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException) GroupIdentifier(org.signal.zkgroup.groups.GroupIdentifier) UntrustedIdentityException(org.whispersystems.signalservice.api.crypto.UntrustedIdentityException) CALL_INCOMING(org.thoughtcrime.securesms.events.WebRtcViewModel.State.CALL_INCOMING) ResultReceiver(android.os.ResultReceiver) Collections(java.util.Collections) InvalidInputException(org.signal.zkgroup.InvalidInputException) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) UntrustedIdentityException(org.whispersystems.signalservice.api.crypto.UntrustedIdentityException) Recipient(org.thoughtcrime.securesms.recipients.Recipient) IOException(java.io.IOException) SendMessageResult(org.whispersystems.signalservice.api.messages.SendMessageResult) GroupId(org.thoughtcrime.securesms.groups.GroupId) GroupIdentifier(org.signal.zkgroup.groups.GroupIdentifier) SignalServiceCallMessage(org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage) RecipientAccessList(org.thoughtcrime.securesms.util.RecipientAccessList) OpaqueMessage(org.whispersystems.signalservice.api.messages.calls.OpaqueMessage)

Example 28 with GroupId

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

the class SignalCallManager method peekGroupCall.

public void peekGroupCall(@NonNull RecipientId id) {
    if (callManager == null) {
        Log.i(TAG, "Unable to peekGroupCall, call manager is null");
        return;
    }
    networkExecutor.execute(() -> {
        try {
            Recipient group = Recipient.resolved(id);
            GroupId.V2 groupId = group.requireGroupId().requireV2();
            GroupExternalCredential credential = GroupManager.getGroupExternalCredential(context, groupId);
            List<GroupCall.GroupMemberInfo> members = Stream.of(GroupManager.getUuidCipherTexts(context, groupId)).map(entry -> new GroupCall.GroupMemberInfo(entry.getKey(), entry.getValue().serialize())).toList();
            callManager.peekGroupCall(SignalStore.internalValues().groupCallingServer(), credential.getTokenBytes().toByteArray(), members, peekInfo -> {
                Long threadId = SignalDatabase.threads().getThreadIdFor(group.getId());
                if (threadId != null) {
                    SignalDatabase.sms().updatePreviousGroupCall(threadId, peekInfo.getEraId(), peekInfo.getJoinedMembers(), WebRtcUtil.isCallFull(peekInfo));
                    ApplicationDependencies.getMessageNotifier().updateNotification(context, threadId, true, 0, BubbleUtil.BubbleState.HIDDEN);
                    EventBus.getDefault().postSticky(new GroupCallPeekEvent(id, peekInfo.getEraId(), peekInfo.getDeviceCount(), peekInfo.getMaxDevices()));
                }
            });
        } catch (IOException | VerificationFailedException | CallException e) {
            Log.e(TAG, "error peeking from active conversation", e);
        }
    });
}
Also used : SignalStore(org.thoughtcrime.securesms.keyvalue.SignalStore) SignalAudioManager(org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager) SignalServiceAccountManager(org.whispersystems.signalservice.api.SignalServiceAccountManager) NetworkRoute(org.signal.ringrtc.NetworkRoute) BubbleUtil(org.thoughtcrime.securesms.util.BubbleUtil) SendMessageResult(org.whispersystems.signalservice.api.messages.SendMessageResult) CallingResponse(org.whispersystems.signalservice.api.messages.calls.CallingResponse) TurnServerInfo(org.whispersystems.signalservice.api.messages.calls.TurnServerInfo) NonNull(androidx.annotation.NonNull) RecipientUtil(org.thoughtcrime.securesms.recipients.RecipientUtil) CallException(org.signal.ringrtc.CallException) WebRtcCallActivity(org.thoughtcrime.securesms.WebRtcCallActivity) CallManager(org.signal.ringrtc.CallManager) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) NetworkUtil(org.thoughtcrime.securesms.util.NetworkUtil) Recipient(org.thoughtcrime.securesms.recipients.Recipient) IDLE(org.thoughtcrime.securesms.events.WebRtcViewModel.GroupCallState.IDLE) SignalExecutors(org.signal.core.util.concurrent.SignalExecutors) WebRtcUtil.getUrgencyFromCallUrgency(org.thoughtcrime.securesms.service.webrtc.WebRtcUtil.getUrgencyFromCallUrgency) GroupExternalCredential(org.signal.storageservice.protos.groups.GroupExternalCredential) ACI(org.whispersystems.signalservice.api.push.ACI) HttpHeader(org.signal.ringrtc.HttpHeader) ApplicationDependencies(org.thoughtcrime.securesms.dependencies.ApplicationDependencies) Collection(java.util.Collection) GroupCallUpdateSendJob(org.thoughtcrime.securesms.jobs.GroupCallUpdateSendJob) Set(java.util.Set) UnidentifiedAccessUtil(org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil) UUID(java.util.UUID) GroupDatabase(org.thoughtcrime.securesms.database.GroupDatabase) UNTRUSTED_IDENTITY(org.thoughtcrime.securesms.events.WebRtcViewModel.State.UNTRUSTED_IDENTITY) Collectors(java.util.stream.Collectors) Executors(java.util.concurrent.Executors) InvalidInputException(org.signal.zkgroup.InvalidInputException) GroupCall(org.signal.ringrtc.GroupCall) Log(org.signal.core.util.logging.Log) List(java.util.List) Nullable(androidx.annotation.Nullable) Application(android.app.Application) GroupId(org.thoughtcrime.securesms.groups.GroupId) CallId(org.signal.ringrtc.CallId) CameraEventListener(org.thoughtcrime.securesms.ringrtc.CameraEventListener) Context(android.content.Context) RecipientAccessList(org.thoughtcrime.securesms.util.RecipientAccessList) SignalDatabase(org.thoughtcrime.securesms.database.SignalDatabase) RemotePeer(org.thoughtcrime.securesms.ringrtc.RemotePeer) Stream(com.annimon.stream.Stream) Remote(org.signal.ringrtc.Remote) Util(org.thoughtcrime.securesms.util.Util) VerificationFailedException(org.signal.zkgroup.VerificationFailedException) Intent(android.content.Intent) AppForegroundObserver(org.thoughtcrime.securesms.util.AppForegroundObserver) RetrieveProfileJob(org.thoughtcrime.securesms.jobs.RetrieveProfileJob) NETWORK_FAILURE(org.thoughtcrime.securesms.events.WebRtcViewModel.State.NETWORK_FAILURE) OfferMessage(org.whispersystems.signalservice.api.messages.calls.OfferMessage) LockManager(org.thoughtcrime.securesms.webrtc.locks.LockManager) TextSecurePreferences(org.thoughtcrime.securesms.util.TextSecurePreferences) OpaqueMessage(org.whispersystems.signalservice.api.messages.calls.OpaqueMessage) GroupManager(org.thoughtcrime.securesms.groups.GroupManager) CameraState(org.thoughtcrime.securesms.ringrtc.CameraState) Pair(org.whispersystems.libsignal.util.Pair) EventBus(org.greenrobot.eventbus.EventBus) SignalServiceCallMessage(org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage) Build(android.os.Build) LinkedList(java.util.LinkedList) GroupSendUtil(org.thoughtcrime.securesms.messages.GroupSendUtil) WebRtcServiceState(org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState) ExecutorService(java.util.concurrent.ExecutorService) SignalServiceMessageSender(org.whispersystems.signalservice.api.SignalServiceMessageSender) PeerConnection(org.webrtc.PeerConnection) Executor(java.util.concurrent.Executor) WebRtcViewModel(org.thoughtcrime.securesms.events.WebRtcViewModel) IOException(java.io.IOException) NO_SUCH_USER(org.thoughtcrime.securesms.events.WebRtcViewModel.State.NO_SUCH_USER) GroupCallPeekEvent(org.thoughtcrime.securesms.events.GroupCallPeekEvent) Optional(org.whispersystems.libsignal.util.guava.Optional) UnregisteredUserException(org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException) GroupIdentifier(org.signal.zkgroup.groups.GroupIdentifier) UntrustedIdentityException(org.whispersystems.signalservice.api.crypto.UntrustedIdentityException) CALL_INCOMING(org.thoughtcrime.securesms.events.WebRtcViewModel.State.CALL_INCOMING) ResultReceiver(android.os.ResultReceiver) Collections(java.util.Collections) GroupCallPeekEvent(org.thoughtcrime.securesms.events.GroupCallPeekEvent) CallException(org.signal.ringrtc.CallException) Recipient(org.thoughtcrime.securesms.recipients.Recipient) IOException(java.io.IOException) GroupExternalCredential(org.signal.storageservice.protos.groups.GroupExternalCredential) GroupId(org.thoughtcrime.securesms.groups.GroupId) VerificationFailedException(org.signal.zkgroup.VerificationFailedException)

Example 29 with GroupId

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

the class GroupSendUtil method sendMessage.

/**
 * Handles all of the logic of sending to a group. Will do sender key sends and legacy 1:1 sends as-needed, and give you back a list of
 * {@link SendMessageResult}s just like we're used to.
 *
 * @param groupId The groupId of the group you're sending to, or null if you're sending to a collection of recipients not joined by a group.
 * @param isRecipientUpdate True if you've already sent this message to some recipients in the past, otherwise false.
 */
@WorkerThread
private static List<SendMessageResult> sendMessage(@NonNull Context context, @Nullable GroupId.V2 groupId, @Nullable MessageId relatedMessageId, @NonNull List<Recipient> allTargets, boolean isRecipientUpdate, @NonNull SendOperation sendOperation, @Nullable CancelationSignal cancelationSignal) throws IOException, UntrustedIdentityException {
    Log.i(TAG, "Starting group send. GroupId: " + (groupId != null ? groupId.toString() : "none") + ", RelatedMessageId: " + (relatedMessageId != null ? relatedMessageId.toString() : "none") + ", Targets: " + allTargets.size() + ", RecipientUpdate: " + isRecipientUpdate + ", Operation: " + sendOperation.getClass().getSimpleName());
    Set<Recipient> unregisteredTargets = allTargets.stream().filter(Recipient::isUnregistered).collect(Collectors.toSet());
    List<Recipient> registeredTargets = allTargets.stream().filter(r -> !unregisteredTargets.contains(r)).collect(Collectors.toList());
    RecipientData recipients = new RecipientData(context, registeredTargets);
    Optional<GroupRecord> groupRecord = groupId != null ? SignalDatabase.groups().getGroup(groupId) : Optional.absent();
    List<Recipient> senderKeyTargets = new LinkedList<>();
    List<Recipient> legacyTargets = new LinkedList<>();
    for (Recipient recipient : registeredTargets) {
        Optional<UnidentifiedAccessPair> access = recipients.getAccessPair(recipient.getId());
        boolean validMembership = groupRecord.isPresent() && groupRecord.get().getMembers().contains(recipient.getId());
        if (recipient.getSenderKeyCapability() == Recipient.Capability.SUPPORTED && recipient.hasServiceId() && access.isPresent() && access.get().getTargetUnidentifiedAccess().isPresent() && validMembership) {
            senderKeyTargets.add(recipient);
        } else {
            legacyTargets.add(recipient);
        }
    }
    if (groupId == null) {
        Log.i(TAG, "Recipients not in a group. Using legacy.");
        legacyTargets.addAll(senderKeyTargets);
        senderKeyTargets.clear();
    } else if (Recipient.self().getSenderKeyCapability() != Recipient.Capability.SUPPORTED) {
        Log.i(TAG, "All of our devices do not support sender key. Using legacy.");
        legacyTargets.addAll(senderKeyTargets);
        senderKeyTargets.clear();
    } else if (SignalStore.internalValues().removeSenderKeyMinimum()) {
        Log.i(TAG, "Sender key minimum removed. Using for " + senderKeyTargets.size() + " recipients.");
    } else if (senderKeyTargets.size() < 2) {
        Log.i(TAG, "Too few sender-key-capable users (" + senderKeyTargets.size() + "). Doing all legacy sends.");
        legacyTargets.addAll(senderKeyTargets);
        senderKeyTargets.clear();
    } else {
        Log.i(TAG, "Can use sender key for " + senderKeyTargets.size() + "/" + allTargets.size() + " recipients.");
    }
    if (relatedMessageId != null) {
        SignalLocalMetrics.GroupMessageSend.onSenderKeyStarted(relatedMessageId.getId());
    }
    List<SendMessageResult> allResults = new ArrayList<>(allTargets.size());
    SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
    if (senderKeyTargets.size() > 0 && groupId != null) {
        DistributionId distributionId = SignalDatabase.groups().getOrCreateDistributionId(groupId);
        long keyCreateTime = SenderKeyUtil.getCreateTimeForOurKey(context, distributionId);
        long keyAge = System.currentTimeMillis() - keyCreateTime;
        if (keyCreateTime != -1 && keyAge > FeatureFlags.senderKeyMaxAge()) {
            Log.w(TAG, "DistributionId " + distributionId + " was created at " + keyCreateTime + " and is " + (keyAge) + " ms old (~" + TimeUnit.MILLISECONDS.toDays(keyAge) + " days). Rotating.");
            SenderKeyUtil.rotateOurKey(context, distributionId);
        }
        try {
            List<SignalServiceAddress> targets = senderKeyTargets.stream().map(r -> recipients.getAddress(r.getId())).collect(Collectors.toList());
            List<UnidentifiedAccess> access = senderKeyTargets.stream().map(r -> recipients.requireAccess(r.getId())).collect(Collectors.toList());
            List<SendMessageResult> results = sendOperation.sendWithSenderKey(messageSender, distributionId, targets, access, isRecipientUpdate);
            allResults.addAll(results);
            int successCount = (int) results.stream().filter(SendMessageResult::isSuccess).count();
            Log.d(TAG, "Successfully sent using sender key to " + successCount + "/" + targets.size() + " sender key targets.");
            if (sendOperation.shouldIncludeInMessageLog()) {
                SignalDatabase.messageLog().insertIfPossible(sendOperation.getSentTimestamp(), senderKeyTargets, results, sendOperation.getContentHint(), sendOperation.getRelatedMessageId());
            }
            if (relatedMessageId != null) {
                SignalLocalMetrics.GroupMessageSend.onSenderKeyMslInserted(relatedMessageId.getId());
            }
        } catch (InvalidUnidentifiedAccessHeaderException e) {
            Log.w(TAG, "Someone had a bad UD header. Falling back to legacy sends.", e);
            legacyTargets.addAll(senderKeyTargets);
        } catch (NoSessionException e) {
            Log.w(TAG, "No session. Falling back to legacy sends.", e);
            legacyTargets.addAll(senderKeyTargets);
        } catch (InvalidKeyException e) {
            Log.w(TAG, "Invalid key. Falling back to legacy sends.", e);
            legacyTargets.addAll(senderKeyTargets);
        } catch (InvalidRegistrationIdException e) {
            Log.w(TAG, "Invalid registrationId. Falling back to legacy sends.", e);
            legacyTargets.addAll(senderKeyTargets);
        } catch (NotFoundException e) {
            Log.w(TAG, "Someone was unregistered. Falling back to legacy sends.", e);
            legacyTargets.addAll(senderKeyTargets);
        }
    } else if (relatedMessageId != null) {
        SignalLocalMetrics.GroupMessageSend.onSenderKeyShared(relatedMessageId.getId());
        SignalLocalMetrics.GroupMessageSend.onSenderKeyEncrypted(relatedMessageId.getId());
        SignalLocalMetrics.GroupMessageSend.onSenderKeyMessageSent(relatedMessageId.getId());
        SignalLocalMetrics.GroupMessageSend.onSenderKeySyncSent(relatedMessageId.getId());
        SignalLocalMetrics.GroupMessageSend.onSenderKeyMslInserted(relatedMessageId.getId());
    }
    if (cancelationSignal != null && cancelationSignal.isCanceled()) {
        throw new CancelationException();
    }
    boolean onlyTargetIsSelfWithLinkedDevice = legacyTargets.isEmpty() && senderKeyTargets.isEmpty() && TextSecurePreferences.isMultiDevice(context);
    if (legacyTargets.size() > 0 || onlyTargetIsSelfWithLinkedDevice) {
        if (legacyTargets.size() > 0) {
            Log.i(TAG, "Need to do " + legacyTargets.size() + " legacy sends.");
        } else {
            Log.i(TAG, "Need to do a legacy send to send a sync message for a group of only ourselves.");
        }
        List<SignalServiceAddress> targets = legacyTargets.stream().map(r -> recipients.getAddress(r.getId())).collect(Collectors.toList());
        List<Optional<UnidentifiedAccessPair>> access = legacyTargets.stream().map(r -> recipients.getAccessPair(r.getId())).collect(Collectors.toList());
        boolean recipientUpdate = isRecipientUpdate || allResults.size() > 0;
        final MessageSendLogDatabase messageLogDatabase = SignalDatabase.messageLog();
        final AtomicLong entryId = new AtomicLong(-1);
        final boolean includeInMessageLog = sendOperation.shouldIncludeInMessageLog();
        List<SendMessageResult> results = sendOperation.sendLegacy(messageSender, targets, access, recipientUpdate, result -> {
            if (!includeInMessageLog) {
                return;
            }
            synchronized (entryId) {
                if (entryId.get() == -1) {
                    entryId.set(messageLogDatabase.insertIfPossible(recipients.requireRecipientId(result.getAddress()), sendOperation.getSentTimestamp(), result, sendOperation.getContentHint(), sendOperation.getRelatedMessageId()));
                } else {
                    messageLogDatabase.addRecipientToExistingEntryIfPossible(entryId.get(), recipients.requireRecipientId(result.getAddress()), result);
                }
            }
        }, cancelationSignal);
        allResults.addAll(results);
        int successCount = (int) results.stream().filter(SendMessageResult::isSuccess).count();
        Log.d(TAG, "Successfully sent using 1:1 to " + successCount + "/" + targets.size() + " legacy targets.");
    } else if (relatedMessageId != null) {
        SignalLocalMetrics.GroupMessageSend.onLegacyMessageSent(relatedMessageId.getId());
        SignalLocalMetrics.GroupMessageSend.onLegacySyncFinished(relatedMessageId.getId());
    }
    if (unregisteredTargets.size() > 0) {
        Log.w(TAG, "There are " + unregisteredTargets.size() + " unregistered targets. Including failure results.");
        List<SendMessageResult> unregisteredResults = unregisteredTargets.stream().filter(Recipient::hasServiceId).map(t -> SendMessageResult.unregisteredFailure(new SignalServiceAddress(t.requireServiceId(), t.getE164().orNull()))).collect(Collectors.toList());
        if (unregisteredResults.size() < unregisteredTargets.size()) {
            Log.w(TAG, "There are " + (unregisteredTargets.size() - unregisteredResults.size()) + " targets that have no UUID! Cannot report a failure for them.");
        }
        allResults.addAll(unregisteredResults);
    }
    return allResults;
}
Also used : SignalStore(org.thoughtcrime.securesms.keyvalue.SignalStore) SignalServiceDataMessage(org.whispersystems.signalservice.api.messages.SignalServiceDataMessage) SendMessageResult(org.whispersystems.signalservice.api.messages.SendMessageResult) NonNull(androidx.annotation.NonNull) RecipientUtil(org.thoughtcrime.securesms.recipients.RecipientUtil) SignalServiceAddress(org.whispersystems.signalservice.api.push.SignalServiceAddress) NotFoundException(org.whispersystems.signalservice.api.push.exceptions.NotFoundException) SenderKeyUtil(org.thoughtcrime.securesms.crypto.SenderKeyUtil) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) Map(java.util.Map) Recipient(org.thoughtcrime.securesms.recipients.Recipient) LegacyGroupEvents(org.whispersystems.signalservice.api.SignalServiceMessageSender.LegacyGroupEvents) PartialSendCompleteListener(org.whispersystems.signalservice.internal.push.http.PartialSendCompleteListener) ApplicationDependencies(org.thoughtcrime.securesms.dependencies.ApplicationDependencies) InvalidUnidentifiedAccessHeaderException(org.whispersystems.signalservice.internal.push.exceptions.InvalidUnidentifiedAccessHeaderException) Set(java.util.Set) UnidentifiedAccessUtil(org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) Log(org.signal.core.util.logging.Log) FeatureFlags(org.thoughtcrime.securesms.util.FeatureFlags) List(java.util.List) Nullable(androidx.annotation.Nullable) GroupId(org.thoughtcrime.securesms.groups.GroupId) NoSessionException(org.whispersystems.libsignal.NoSessionException) CancelationException(org.whispersystems.signalservice.api.CancelationException) Context(android.content.Context) RecipientAccessList(org.thoughtcrime.securesms.util.RecipientAccessList) SignalDatabase(org.thoughtcrime.securesms.database.SignalDatabase) ContentHint(org.whispersystems.signalservice.api.crypto.ContentHint) SignalServiceTypingMessage(org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage) SignalLocalMetrics(org.thoughtcrime.securesms.util.SignalLocalMetrics) WorkerThread(androidx.annotation.WorkerThread) GroupRecord(org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord) SenderKeyGroupEvents(org.whispersystems.signalservice.api.SignalServiceMessageSender.SenderKeyGroupEvents) CancelationSignal(org.whispersystems.signalservice.internal.push.http.CancelationSignal) HashMap(java.util.HashMap) InvalidRegistrationIdException(org.whispersystems.libsignal.InvalidRegistrationIdException) InvalidKeyException(org.whispersystems.libsignal.InvalidKeyException) UnidentifiedAccessPair(org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair) ArrayList(java.util.ArrayList) TextSecurePreferences(org.thoughtcrime.securesms.util.TextSecurePreferences) UnidentifiedAccess(org.whispersystems.signalservice.api.crypto.UnidentifiedAccess) SignalServiceCallMessage(org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage) MessageSendLogDatabase(org.thoughtcrime.securesms.database.MessageSendLogDatabase) LinkedList(java.util.LinkedList) DistributionId(org.whispersystems.signalservice.api.push.DistributionId) SignalServiceMessageSender(org.whispersystems.signalservice.api.SignalServiceMessageSender) MessageId(org.thoughtcrime.securesms.database.model.MessageId) Iterator(java.util.Iterator) IOException(java.io.IOException) Optional(org.whispersystems.libsignal.util.guava.Optional) TimeUnit(java.util.concurrent.TimeUnit) AtomicLong(java.util.concurrent.atomic.AtomicLong) UntrustedIdentityException(org.whispersystems.signalservice.api.crypto.UntrustedIdentityException) Collections(java.util.Collections) ArrayList(java.util.ArrayList) SignalServiceMessageSender(org.whispersystems.signalservice.api.SignalServiceMessageSender) NotFoundException(org.whispersystems.signalservice.api.push.exceptions.NotFoundException) MessageSendLogDatabase(org.thoughtcrime.securesms.database.MessageSendLogDatabase) GroupRecord(org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord) NoSessionException(org.whispersystems.libsignal.NoSessionException) CancelationException(org.whispersystems.signalservice.api.CancelationException) SignalServiceAddress(org.whispersystems.signalservice.api.push.SignalServiceAddress) Optional(org.whispersystems.libsignal.util.guava.Optional) InvalidRegistrationIdException(org.whispersystems.libsignal.InvalidRegistrationIdException) Recipient(org.thoughtcrime.securesms.recipients.Recipient) UnidentifiedAccessPair(org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair) DistributionId(org.whispersystems.signalservice.api.push.DistributionId) InvalidKeyException(org.whispersystems.libsignal.InvalidKeyException) LinkedList(java.util.LinkedList) SendMessageResult(org.whispersystems.signalservice.api.messages.SendMessageResult) ContentHint(org.whispersystems.signalservice.api.crypto.ContentHint) UnidentifiedAccess(org.whispersystems.signalservice.api.crypto.UnidentifiedAccess) AtomicLong(java.util.concurrent.atomic.AtomicLong) InvalidUnidentifiedAccessHeaderException(org.whispersystems.signalservice.internal.push.exceptions.InvalidUnidentifiedAccessHeaderException) WorkerThread(androidx.annotation.WorkerThread)

Example 30 with GroupId

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

the class MessageContentProcessor method handleSynchronizeMessageRequestResponse.

private void handleSynchronizeMessageRequestResponse(@NonNull MessageRequestResponseMessage response, long envelopeTimestamp) throws BadGroupIdException {
    log(envelopeTimestamp, "Synchronize message request response.");
    RecipientDatabase recipientDatabase = SignalDatabase.recipients();
    ThreadDatabase threadDatabase = SignalDatabase.threads();
    Recipient recipient;
    if (response.getPerson().isPresent()) {
        recipient = Recipient.externalPush(response.getPerson().get());
    } else if (response.getGroupId().isPresent()) {
        GroupId groupId = GroupId.v1(response.getGroupId().get());
        recipient = Recipient.externalPossiblyMigratedGroup(context, groupId);
    } else {
        warn("Message request response was missing a thread recipient! Skipping.");
        return;
    }
    long threadId = threadDatabase.getOrCreateThreadIdFor(recipient);
    switch(response.getType()) {
        case ACCEPT:
            recipientDatabase.setProfileSharing(recipient.getId(), true);
            recipientDatabase.setBlocked(recipient.getId(), false);
            break;
        case DELETE:
            recipientDatabase.setProfileSharing(recipient.getId(), false);
            if (threadId > 0)
                threadDatabase.deleteConversation(threadId);
            break;
        case BLOCK:
            recipientDatabase.setBlocked(recipient.getId(), true);
            recipientDatabase.setProfileSharing(recipient.getId(), false);
            break;
        case BLOCK_AND_DELETE:
            recipientDatabase.setBlocked(recipient.getId(), true);
            recipientDatabase.setProfileSharing(recipient.getId(), false);
            if (threadId > 0)
                threadDatabase.deleteConversation(threadId);
            break;
        default:
            warn("Got an unknown response type! Skipping");
            break;
    }
}
Also used : RecipientDatabase(org.thoughtcrime.securesms.database.RecipientDatabase) Recipient(org.thoughtcrime.securesms.recipients.Recipient) ThreadDatabase(org.thoughtcrime.securesms.database.ThreadDatabase) GroupId(org.thoughtcrime.securesms.groups.GroupId)

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