Search in sources :

Example 51 with RecipientId

use of org.thoughtcrime.securesms.recipients.RecipientId in project Signal-Android by WhisperSystems.

the class PushTextSendJob method onPushSend.

@Override
public void onPushSend() throws IOException, NoSuchMessageException, UndeliverableMessageException, RetryLaterException {
    SignalLocalMetrics.IndividualMessageSend.onJobStarted(messageId);
    ExpiringMessageManager expirationManager = ApplicationDependencies.getExpiringMessageManager();
    MessageDatabase database = SignalDatabase.sms();
    SmsMessageRecord record = database.getSmsMessage(messageId);
    if (!record.isPending() && !record.isFailed()) {
        warn(TAG, String.valueOf(record.getDateSent()), "Message " + messageId + " was already sent. Ignoring.");
        return;
    }
    try {
        log(TAG, String.valueOf(record.getDateSent()), "Sending message: " + messageId + ",  Recipient: " + record.getRecipient().getId() + ", Thread: " + record.getThreadId());
        RecipientUtil.shareProfileIfFirstSecureMessage(context, record.getRecipient());
        Recipient recipient = record.getRecipient().resolve();
        byte[] profileKey = recipient.getProfileKey();
        UnidentifiedAccessMode accessMode = recipient.getUnidentifiedAccessMode();
        boolean unidentified = deliver(record);
        database.markAsSent(messageId, true);
        database.markUnidentified(messageId, unidentified);
        if (recipient.isSelf()) {
            SyncMessageId id = new SyncMessageId(recipient.getId(), record.getDateSent());
            SignalDatabase.mmsSms().incrementDeliveryReceiptCount(id, System.currentTimeMillis());
            SignalDatabase.mmsSms().incrementReadReceiptCount(id, System.currentTimeMillis());
        }
        if (unidentified && accessMode == UnidentifiedAccessMode.UNKNOWN && profileKey == null) {
            log(TAG, String.valueOf(record.getDateSent()), "Marking recipient as UD-unrestricted following a UD send.");
            SignalDatabase.recipients().setUnidentifiedAccessMode(recipient.getId(), UnidentifiedAccessMode.UNRESTRICTED);
        } else if (unidentified && accessMode == UnidentifiedAccessMode.UNKNOWN) {
            log(TAG, String.valueOf(record.getDateSent()), "Marking recipient as UD-enabled following a UD send.");
            SignalDatabase.recipients().setUnidentifiedAccessMode(recipient.getId(), UnidentifiedAccessMode.ENABLED);
        } else if (!unidentified && accessMode != UnidentifiedAccessMode.DISABLED) {
            log(TAG, String.valueOf(record.getDateSent()), "Marking recipient as UD-disabled following a non-UD send.");
            SignalDatabase.recipients().setUnidentifiedAccessMode(recipient.getId(), UnidentifiedAccessMode.DISABLED);
        }
        if (record.getExpiresIn() > 0) {
            database.markExpireStarted(messageId);
            expirationManager.scheduleDeletion(record.getId(), record.isMms(), record.getExpiresIn());
        }
        log(TAG, String.valueOf(record.getDateSent()), "Sent message: " + messageId);
    } catch (InsecureFallbackApprovalException e) {
        warn(TAG, String.valueOf(record.getDateSent()), "Failure", e);
        database.markAsPendingInsecureSmsFallback(record.getId());
        ApplicationDependencies.getMessageNotifier().notifyMessageDeliveryFailed(context, record.getRecipient(), record.getThreadId());
        ApplicationDependencies.getJobManager().add(new DirectoryRefreshJob(false));
    } catch (UntrustedIdentityException e) {
        warn(TAG, String.valueOf(record.getDateSent()), "Failure", e);
        RecipientId recipientId = Recipient.external(context, e.getIdentifier()).getId();
        database.addMismatchedIdentity(record.getId(), recipientId, e.getIdentityKey());
        database.markAsSentFailed(record.getId());
        database.markAsPush(record.getId());
        RetrieveProfileJob.enqueue(recipientId);
    } catch (ProofRequiredException e) {
        handleProofRequiredException(e, record.getRecipient(), record.getThreadId(), messageId, false);
    }
    SignalLocalMetrics.IndividualMessageSend.onJobFinished(messageId);
}
Also used : MessageDatabase(org.thoughtcrime.securesms.database.MessageDatabase) UntrustedIdentityException(org.whispersystems.signalservice.api.crypto.UntrustedIdentityException) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) SmsMessageRecord(org.thoughtcrime.securesms.database.model.SmsMessageRecord) ExpiringMessageManager(org.thoughtcrime.securesms.service.ExpiringMessageManager) Recipient(org.thoughtcrime.securesms.recipients.Recipient) ProofRequiredException(org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException) UnidentifiedAccessMode(org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessMode) InsecureFallbackApprovalException(org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException) SyncMessageId(org.thoughtcrime.securesms.database.MessageDatabase.SyncMessageId)

Example 52 with RecipientId

use of org.thoughtcrime.securesms.recipients.RecipientId in project Signal-Android by WhisperSystems.

the class RemoteDeleteSendJob method create.

@WorkerThread
@NonNull
public static RemoteDeleteSendJob create(@NonNull Context context, long messageId, boolean isMms) throws NoSuchMessageException {
    MessageRecord message = isMms ? SignalDatabase.mms().getMessageRecord(messageId) : SignalDatabase.sms().getSmsMessage(messageId);
    Recipient conversationRecipient = SignalDatabase.threads().getRecipientForThreadId(message.getThreadId());
    if (conversationRecipient == null) {
        throw new AssertionError("We have a message, but couldn't find the thread!");
    }
    List<RecipientId> recipients = conversationRecipient.isGroup() ? Stream.of(RecipientUtil.getEligibleForSending(conversationRecipient.getParticipants())).map(Recipient::getId).toList() : Stream.of(conversationRecipient.getId()).toList();
    recipients.remove(Recipient.self().getId());
    return new RemoteDeleteSendJob(messageId, isMms, recipients, recipients.size(), new Parameters.Builder().setQueue(conversationRecipient.getId().toQueueKey()).setLifespan(TimeUnit.DAYS.toMillis(1)).setMaxAttempts(Parameters.UNLIMITED).build());
}
Also used : RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) MessageRecord(org.thoughtcrime.securesms.database.model.MessageRecord) Recipient(org.thoughtcrime.securesms.recipients.Recipient) WorkerThread(androidx.annotation.WorkerThread) NonNull(androidx.annotation.NonNull)

Example 53 with RecipientId

use of org.thoughtcrime.securesms.recipients.RecipientId in project Signal-Android by WhisperSystems.

the class RetrieveProfileJob method forRecipients.

/**
 * Works for any RecipientId, whether it's an individual, group, or yourself.
 *
 * @return A list of length 2 or less. Two iff you are in the recipients.
 */
@WorkerThread
@NonNull
public static List<Job> forRecipients(@NonNull Set<RecipientId> recipientIds) {
    Context context = ApplicationDependencies.getApplication();
    Set<RecipientId> combined = new HashSet<>(recipientIds.size());
    boolean includeSelf = false;
    for (RecipientId recipientId : recipientIds) {
        Recipient recipient = Recipient.resolved(recipientId);
        if (recipient.isSelf()) {
            includeSelf = true;
        } else if (recipient.isGroup()) {
            List<Recipient> recipients = SignalDatabase.groups().getGroupMembers(recipient.requireGroupId(), GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF);
            combined.addAll(Stream.of(recipients).map(Recipient::getId).toList());
        } else {
            combined.add(recipientId);
        }
    }
    List<Job> jobs = new ArrayList<>(2);
    if (includeSelf) {
        jobs.add(new RefreshOwnProfileJob());
    }
    if (combined.size() > 0) {
        jobs.add(new RetrieveProfileJob(combined));
    }
    return jobs;
}
Also used : Context(android.content.Context) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) ArrayList(java.util.ArrayList) Recipient(org.thoughtcrime.securesms.recipients.Recipient) List(java.util.List) ArrayList(java.util.ArrayList) Job(org.thoughtcrime.securesms.jobmanager.Job) HashSet(java.util.HashSet) WorkerThread(androidx.annotation.WorkerThread) NonNull(androidx.annotation.NonNull)

Example 54 with RecipientId

use of org.thoughtcrime.securesms.recipients.RecipientId in project Signal-Android by WhisperSystems.

the class ReactionSendJob method onRun.

@Override
protected void onRun() throws Exception {
    if (!Recipient.self().isRegistered()) {
        throw new NotPushRegisteredException();
    }
    ReactionDatabase reactionDatabase = SignalDatabase.reactions();
    MessageRecord message;
    if (messageId.isMms()) {
        message = SignalDatabase.mms().getMessageRecord(messageId.getId());
    } else {
        message = SignalDatabase.sms().getSmsMessage(messageId.getId());
    }
    Recipient targetAuthor = message.isOutgoing() ? Recipient.self() : message.getIndividualRecipient();
    long targetSentTimestamp = message.getDateSent();
    if (targetAuthor.getId().equals(SignalStore.releaseChannelValues().getReleaseChannelRecipientId())) {
        return;
    }
    if (!remove && !reactionDatabase.hasReaction(messageId, reaction)) {
        Log.w(TAG, "Went to add a reaction, but it's no longer present on the message!");
        return;
    }
    if (remove && reactionDatabase.hasReaction(messageId, reaction)) {
        Log.w(TAG, "Went to remove a reaction, but it's still there!");
        return;
    }
    Recipient conversationRecipient = SignalDatabase.threads().getRecipientForThreadId(message.getThreadId());
    if (conversationRecipient == null) {
        throw new AssertionError("We have a message, but couldn't find the thread!");
    }
    if (conversationRecipient.isPushV1Group() || conversationRecipient.isMmsGroup()) {
        Log.w(TAG, "Cannot send reactions to legacy groups.");
        return;
    }
    List<Recipient> resolved = recipients.stream().map(Recipient::resolved).collect(Collectors.toList());
    List<RecipientId> unregistered = resolved.stream().filter(Recipient::isUnregistered).map(Recipient::getId).collect(Collectors.toList());
    List<Recipient> destinations = resolved.stream().filter(Recipient::isMaybeRegistered).collect(Collectors.toList());
    List<Recipient> completions = deliver(conversationRecipient, destinations, targetAuthor, targetSentTimestamp);
    recipients.removeAll(unregistered);
    recipients.removeAll(completions.stream().map(Recipient::getId).collect(Collectors.toList()));
    Log.i(TAG, "Completed now: " + completions.size() + ", Remaining: " + recipients.size());
    if (!recipients.isEmpty()) {
        Log.w(TAG, "Still need to send to " + recipients.size() + " recipients. Retrying.");
        throw new RetryLaterException();
    }
}
Also used : RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) NotPushRegisteredException(org.thoughtcrime.securesms.net.NotPushRegisteredException) MessageRecord(org.thoughtcrime.securesms.database.model.MessageRecord) ReactionDatabase(org.thoughtcrime.securesms.database.ReactionDatabase) Recipient(org.thoughtcrime.securesms.recipients.Recipient) RetryLaterException(org.thoughtcrime.securesms.transport.RetryLaterException)

Example 55 with RecipientId

use of org.thoughtcrime.securesms.recipients.RecipientId in project Signal-Android by WhisperSystems.

the class ResendMessageJob method onRun.

@Override
protected void onRun() throws Exception {
    if (SignalStore.internalValues().delayResends()) {
        Log.w(TAG, "Delaying resend by 10 sec because of an internal preference.");
        ThreadUtil.sleep(10000);
    }
    SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
    Recipient recipient = Recipient.resolved(recipientId);
    if (recipient.isUnregistered()) {
        Log.w(TAG, recipient.getId() + " is unregistered!");
        return;
    }
    SignalServiceAddress address = RecipientUtil.toSignalServiceAddress(context, recipient);
    Optional<UnidentifiedAccessPair> access = UnidentifiedAccessUtil.getAccessFor(context, recipient);
    Content contentToSend = content;
    if (distributionId != null) {
        Optional<GroupRecord> groupRecord = SignalDatabase.groups().getGroupByDistributionId(distributionId);
        if (!groupRecord.isPresent()) {
            Log.w(TAG, "Could not find a matching group for the distributionId! Skipping message send.");
            return;
        } else if (!groupRecord.get().getMembers().contains(recipientId)) {
            Log.w(TAG, "The target user is no longer in the group! Skipping message send.");
            return;
        }
        SenderKeyDistributionMessage senderKeyDistributionMessage = messageSender.getOrCreateNewGroupSession(distributionId);
        ByteString distributionBytes = ByteString.copyFrom(senderKeyDistributionMessage.serialize());
        contentToSend = contentToSend.toBuilder().setSenderKeyDistributionMessage(distributionBytes).build();
    }
    SendMessageResult result = messageSender.resendContent(address, access, sentTimestamp, contentToSend, contentHint, Optional.fromNullable(groupId).transform(GroupId::getDecodedId));
    if (result.isSuccess() && distributionId != null) {
        List<SignalProtocolAddress> addresses = result.getSuccess().getDevices().stream().map(device -> recipient.requireServiceId().toProtocolAddress(device)).collect(Collectors.toList());
        ApplicationDependencies.getProtocolStore().aci().markSenderKeySharedWith(distributionId, addresses);
    }
}
Also used : SignalStore(org.thoughtcrime.securesms.keyvalue.SignalStore) SignalDatabase(org.thoughtcrime.securesms.database.SignalDatabase) ContentHint(org.whispersystems.signalservice.api.crypto.ContentHint) SendMessageResult(org.whispersystems.signalservice.api.messages.SendMessageResult) NonNull(androidx.annotation.NonNull) Data(org.thoughtcrime.securesms.jobmanager.Data) RecipientUtil(org.thoughtcrime.securesms.recipients.RecipientUtil) GroupRecord(org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord) 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) InvalidProtocolBufferException(com.google.protobuf.InvalidProtocolBufferException) PushNetworkException(org.whispersystems.signalservice.api.push.exceptions.PushNetworkException) 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) ThreadUtil(org.signal.core.util.ThreadUtil) Collectors(java.util.stream.Collectors) Optional(org.whispersystems.libsignal.util.guava.Optional) ByteString(com.google.protobuf.ByteString) TimeUnit(java.util.concurrent.TimeUnit) Log(org.signal.core.util.logging.Log) List(java.util.List) Nullable(androidx.annotation.Nullable) GroupId(org.thoughtcrime.securesms.groups.GroupId) Content(org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content) Job(org.thoughtcrime.securesms.jobmanager.Job) ByteString(com.google.protobuf.ByteString) SignalServiceMessageSender(org.whispersystems.signalservice.api.SignalServiceMessageSender) Recipient(org.thoughtcrime.securesms.recipients.Recipient) UnidentifiedAccessPair(org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair) GroupRecord(org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord) SendMessageResult(org.whispersystems.signalservice.api.messages.SendMessageResult) Content(org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content) SenderKeyDistributionMessage(org.whispersystems.libsignal.protocol.SenderKeyDistributionMessage) SignalServiceAddress(org.whispersystems.signalservice.api.push.SignalServiceAddress) SignalProtocolAddress(org.whispersystems.libsignal.SignalProtocolAddress)

Aggregations

RecipientId (org.thoughtcrime.securesms.recipients.RecipientId)154 NonNull (androidx.annotation.NonNull)70 Recipient (org.thoughtcrime.securesms.recipients.Recipient)70 List (java.util.List)34 ArrayList (java.util.ArrayList)33 Nullable (androidx.annotation.Nullable)32 Context (android.content.Context)31 Log (org.signal.core.util.logging.Log)31 IOException (java.io.IOException)30 ApplicationDependencies (org.thoughtcrime.securesms.dependencies.ApplicationDependencies)29 WorkerThread (androidx.annotation.WorkerThread)28 Stream (com.annimon.stream.Stream)27 LinkedList (java.util.LinkedList)25 ContentValues (android.content.ContentValues)24 Cursor (android.database.Cursor)24 Collections (java.util.Collections)24 SignalDatabase (org.thoughtcrime.securesms.database.SignalDatabase)24 GroupDatabase (org.thoughtcrime.securesms.database.GroupDatabase)23 Optional (org.whispersystems.libsignal.util.guava.Optional)22 HashSet (java.util.HashSet)21