kopia lustrzana https://github.com/ryukoposting/Signal-Android
156 wiersze
6.8 KiB
Java
156 wiersze
6.8 KiB
Java
package org.thoughtcrime.securesms.jobs;
|
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
import org.signal.core.util.logging.Log;
|
|
import org.signal.libsignal.protocol.SignalProtocolAddress;
|
|
import org.signal.libsignal.protocol.message.SenderKeyDistributionMessage;
|
|
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
|
import org.thoughtcrime.securesms.database.model.DistributionListRecord;
|
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
|
import org.thoughtcrime.securesms.groups.GroupId;
|
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
|
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
|
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
|
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
|
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
|
import org.whispersystems.signalservice.api.messages.SendMessageResult;
|
|
import org.whispersystems.signalservice.api.push.DistributionId;
|
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
|
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
import java.util.Optional;
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.stream.Collectors;
|
|
|
|
/**
|
|
* Sends a {@link SenderKeyDistributionMessage} to a target recipient.
|
|
*
|
|
* Will re-check group membership at send time and send the proper distribution message if they're still a member.
|
|
*/
|
|
public final class SenderKeyDistributionSendJob extends BaseJob {
|
|
|
|
private static final String TAG = Log.tag(SenderKeyDistributionSendJob.class);
|
|
|
|
public static final String KEY = "SenderKeyDistributionSendJob";
|
|
|
|
private static final String KEY_TARGET_RECIPIENT_ID = "recipient_id";
|
|
private static final String KEY_THREAD_RECIPIENT_ID = "thread_recipient_id";
|
|
|
|
private final RecipientId targetRecipientId;
|
|
private final RecipientId threadRecipientId;
|
|
|
|
public SenderKeyDistributionSendJob(@NonNull RecipientId targetRecipientId, RecipientId threadRecipientId) {
|
|
this(targetRecipientId, threadRecipientId, new Parameters.Builder()
|
|
.setQueue(targetRecipientId.toQueueKey())
|
|
.addConstraint(NetworkConstraint.KEY)
|
|
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
|
.setMaxAttempts(Parameters.UNLIMITED)
|
|
.setMaxInstancesForQueue(1)
|
|
.build());
|
|
}
|
|
|
|
private SenderKeyDistributionSendJob(@NonNull RecipientId targetRecipientId, @NonNull RecipientId threadRecipientId, @NonNull Parameters parameters) {
|
|
super(parameters);
|
|
|
|
this.targetRecipientId = targetRecipientId;
|
|
this.threadRecipientId = threadRecipientId;
|
|
}
|
|
|
|
@Override
|
|
public @NonNull Data serialize() {
|
|
return new Data.Builder().putString(KEY_TARGET_RECIPIENT_ID, targetRecipientId.serialize())
|
|
.putString(KEY_THREAD_RECIPIENT_ID, threadRecipientId.serialize())
|
|
.build();
|
|
}
|
|
|
|
@Override
|
|
public @NonNull String getFactoryKey() {
|
|
return KEY;
|
|
}
|
|
|
|
@Override
|
|
protected void onRun() throws Exception {
|
|
Recipient targetRecipient = Recipient.resolved(targetRecipientId);
|
|
Recipient threadRecipient = Recipient.resolved(threadRecipientId);
|
|
|
|
if (targetRecipient.isUnregistered()) {
|
|
Log.w(TAG, threadRecipient.getId() + " not registered!");
|
|
return;
|
|
}
|
|
|
|
GroupId.V2 groupId;
|
|
DistributionId distributionId;
|
|
|
|
if (threadRecipient.isPushV2Group()) {
|
|
groupId = threadRecipient.requireGroupId().requireV2();
|
|
distributionId = SignalDatabase.groups().getOrCreateDistributionId(groupId);
|
|
} else if (threadRecipient.isDistributionList()) {
|
|
groupId = null;
|
|
distributionId = SignalDatabase.distributionLists().getDistributionId(threadRecipientId);
|
|
} else {
|
|
warn(TAG, "Recipient is not a group or distribution list! Skipping.");
|
|
return;
|
|
}
|
|
|
|
if (distributionId == null) {
|
|
warn(TAG, "Failed to find a distributionId! Skipping.");
|
|
return;
|
|
}
|
|
|
|
if (groupId != null && !SignalDatabase.groups().isCurrentMember(groupId, targetRecipientId)) {
|
|
Log.w(TAG, targetRecipientId + " is no longer a member of " + groupId + "! Not sending.");
|
|
return;
|
|
} else if (groupId == null) {
|
|
DistributionListRecord listRecord = SignalDatabase.distributionLists().getList(threadRecipientId);
|
|
|
|
if (listRecord == null || !listRecord.getMembers().contains(targetRecipientId)) {
|
|
Log.w(TAG, targetRecipientId + " is no longer a member of the distribution list! Not sending.");
|
|
return;
|
|
}
|
|
}
|
|
|
|
SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
|
|
List<SignalServiceAddress> address = Collections.singletonList(RecipientUtil.toSignalServiceAddress(context, targetRecipient));
|
|
SenderKeyDistributionMessage message = messageSender.getOrCreateNewGroupSession(distributionId);
|
|
List<Optional<UnidentifiedAccessPair>> access = UnidentifiedAccessUtil.getAccessFor(context, Collections.singletonList(targetRecipient));
|
|
|
|
SendMessageResult result = messageSender.sendSenderKeyDistributionMessage(distributionId, address, access, message, Optional.ofNullable(groupId).map(GroupId::getDecodedId), false, false).get(0);
|
|
|
|
if (result.isSuccess()) {
|
|
List<SignalProtocolAddress> addresses = result.getSuccess()
|
|
.getDevices()
|
|
.stream()
|
|
.map(device -> targetRecipient.requireServiceId().toProtocolAddress(device))
|
|
.collect(Collectors.toList());
|
|
|
|
ApplicationDependencies.getProtocolStore().aci().markSenderKeySharedWith(distributionId, addresses);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected boolean onShouldRetry(@NonNull Exception e) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void onFailure() {
|
|
|
|
}
|
|
|
|
public static final class Factory implements Job.Factory<SenderKeyDistributionSendJob> {
|
|
|
|
@Override
|
|
public @NonNull SenderKeyDistributionSendJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
|
return new SenderKeyDistributionSendJob(RecipientId.from(data.getString(KEY_TARGET_RECIPIENT_ID)),
|
|
RecipientId.from(data.getString(KEY_THREAD_RECIPIENT_ID)),
|
|
parameters);
|
|
}
|
|
}
|
|
}
|