2017-05-20 01:01:40 +00:00
|
|
|
package org.thoughtcrime.securesms.jobs;
|
|
|
|
|
|
|
|
|
|
|
|
import android.content.Context;
|
|
|
|
import android.support.annotation.NonNull;
|
|
|
|
import android.util.Log;
|
|
|
|
|
|
|
|
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
|
2017-06-02 16:49:29 +00:00
|
|
|
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
2017-05-20 01:01:40 +00:00
|
|
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
|
|
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
|
|
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
|
|
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
|
|
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
|
|
|
import org.thoughtcrime.securesms.service.MessageRetrievalService;
|
|
|
|
import org.thoughtcrime.securesms.util.Base64;
|
|
|
|
import org.thoughtcrime.securesms.util.GroupUtil;
|
2017-05-31 21:51:23 +00:00
|
|
|
import org.thoughtcrime.securesms.util.Util;
|
2017-05-20 01:01:40 +00:00
|
|
|
import org.whispersystems.jobqueue.JobParameters;
|
|
|
|
import org.whispersystems.libsignal.IdentityKey;
|
|
|
|
import org.whispersystems.libsignal.InvalidKeyException;
|
|
|
|
import org.whispersystems.libsignal.SignalProtocolAddress;
|
|
|
|
import org.whispersystems.libsignal.state.IdentityKeyStore;
|
2017-06-02 16:49:29 +00:00
|
|
|
import org.whispersystems.libsignal.state.SessionRecord;
|
|
|
|
import org.whispersystems.libsignal.state.SessionStore;
|
2017-05-20 01:01:40 +00:00
|
|
|
import org.whispersystems.signalservice.api.SignalServiceMessagePipe;
|
|
|
|
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
|
|
|
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
|
|
|
import org.whispersystems.signalservice.api.push.SignalServiceProfile;
|
2017-05-31 21:51:23 +00:00
|
|
|
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
2017-05-20 01:01:40 +00:00
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
|
|
|
import javax.inject.Inject;
|
|
|
|
|
|
|
|
import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
|
|
|
|
|
|
|
|
public class RetrieveProfileJob extends ContextJob implements InjectableType {
|
|
|
|
|
|
|
|
private static final String TAG = RetrieveProfileJob.class.getSimpleName();
|
|
|
|
|
|
|
|
@Inject transient SignalServiceMessageReceiver receiver;
|
|
|
|
|
|
|
|
private final long[] recipientIds;
|
|
|
|
|
|
|
|
public RetrieveProfileJob(Context context, Recipients recipients) {
|
|
|
|
super(context, JobParameters.newBuilder()
|
|
|
|
.withRetryCount(3)
|
|
|
|
.create());
|
|
|
|
|
|
|
|
this.recipientIds = recipients.getIds();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onAdded() {}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onRun() throws IOException, InvalidKeyException {
|
2017-05-31 21:51:23 +00:00
|
|
|
try {
|
|
|
|
Recipients recipients = RecipientFactory.getRecipientsForIds(context, recipientIds, true);
|
2017-05-20 01:01:40 +00:00
|
|
|
|
2017-05-31 21:51:23 +00:00
|
|
|
for (Recipient recipient : recipients) {
|
|
|
|
if (recipient.isGroupRecipient()) handleGroupRecipient(recipient);
|
|
|
|
else handleIndividualRecipient(recipient);
|
|
|
|
}
|
|
|
|
} catch (InvalidNumberException e) {
|
|
|
|
Log.w(TAG, e);
|
2017-05-20 01:01:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onShouldRetry(Exception e) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onCanceled() {}
|
|
|
|
|
|
|
|
private void handleIndividualRecipient(Recipient recipient)
|
2017-05-31 21:51:23 +00:00
|
|
|
throws IOException, InvalidKeyException, InvalidNumberException
|
2017-05-20 01:01:40 +00:00
|
|
|
{
|
2017-05-31 21:51:23 +00:00
|
|
|
String number = Util.canonicalizeNumber(context, recipient.getNumber());
|
|
|
|
SignalServiceProfile profile = retrieveProfile(number);
|
2017-05-20 01:01:40 +00:00
|
|
|
IdentityKey identityKey = new IdentityKey(Base64.decode(profile.getIdentityKey()), 0);
|
|
|
|
|
|
|
|
if (!DatabaseFactory.getIdentityDatabase(context)
|
|
|
|
.getIdentity(recipient.getRecipientId())
|
|
|
|
.isPresent())
|
|
|
|
{
|
|
|
|
Log.w(TAG, "Still first use...");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
synchronized (SESSION_LOCK) {
|
2017-06-02 16:49:29 +00:00
|
|
|
IdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(context);
|
|
|
|
SessionStore sessionStore = new TextSecureSessionStore(context);
|
|
|
|
SignalProtocolAddress address = new SignalProtocolAddress(number, 1);
|
|
|
|
|
|
|
|
if (identityKeyStore.saveIdentity(address, identityKey)) {
|
|
|
|
if (sessionStore.containsSession(address)) {
|
|
|
|
SessionRecord sessionRecord = sessionStore.loadSession(address);
|
|
|
|
sessionRecord.archiveCurrentState();
|
|
|
|
|
|
|
|
sessionStore.storeSession(address, sessionRecord);
|
|
|
|
}
|
|
|
|
}
|
2017-05-20 01:01:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void handleGroupRecipient(Recipient group)
|
2017-05-31 21:51:23 +00:00
|
|
|
throws IOException, InvalidKeyException, InvalidNumberException
|
2017-05-20 01:01:40 +00:00
|
|
|
{
|
|
|
|
byte[] groupId = GroupUtil.getDecodedId(group.getNumber());
|
|
|
|
Recipients recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupId, false);
|
|
|
|
|
|
|
|
for (Recipient recipient : recipients) {
|
|
|
|
handleIndividualRecipient(recipient);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private SignalServiceProfile retrieveProfile(@NonNull String number) throws IOException {
|
|
|
|
SignalServiceMessagePipe pipe = MessageRetrievalService.getPipe();
|
|
|
|
|
|
|
|
if (pipe != null) {
|
|
|
|
try {
|
|
|
|
return pipe.getProfile(new SignalServiceAddress(number));
|
|
|
|
} catch (IOException e) {
|
|
|
|
Log.w(TAG, e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return receiver.retrieveProfile(new SignalServiceAddress(number));
|
|
|
|
}
|
|
|
|
}
|