Some identity key handling changes
1) Prefetch identity keys when possible 2) Always accept prefetched keys or keys from incoming messages 3) Block sending only if it's a recent change, or if always block is enabled // FREEBIEpull/1/head
parent
ca701df1e4
commit
d507756821
@ -1,23 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.database.loaders;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.support.v4.content.CursorLoader;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
|
||||||
|
|
||||||
public class IdentityLoader extends CursorLoader {
|
|
||||||
|
|
||||||
private final Context context;
|
|
||||||
|
|
||||||
public IdentityLoader(Context context) {
|
|
||||||
super(context);
|
|
||||||
this.context = context.getApplicationContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Cursor loadInBackground() {
|
|
||||||
return DatabaseFactory.getIdentityDatabase(context).getIdentities();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.jobs;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
|
||||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
|
||||||
import org.thoughtcrime.securesms.sms.IncomingIdentityUpdateMessage;
|
|
||||||
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
|
||||||
import org.whispersystems.jobqueue.JobParameters;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
|
||||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
|
||||||
|
|
||||||
public class IdentityUpdateJob extends MasterSecretJob {
|
|
||||||
|
|
||||||
private static final String TAG = IdentityUpdateJob.class.getSimpleName();
|
|
||||||
|
|
||||||
private final long recipientId;
|
|
||||||
|
|
||||||
public IdentityUpdateJob(Context context, long recipientId) {
|
|
||||||
super(context, JobParameters.newBuilder()
|
|
||||||
.withGroupId("IdentityUpdateJob")
|
|
||||||
.withPersistence()
|
|
||||||
.create());
|
|
||||||
this.recipientId = recipientId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRun(MasterSecret masterSecret) {
|
|
||||||
Recipient recipient = RecipientFactory.getRecipientForId(context, recipientId, true);
|
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFor(context, recipient, true);
|
|
||||||
long time = System.currentTimeMillis();
|
|
||||||
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
|
||||||
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
|
|
||||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
|
||||||
GroupDatabase.Reader reader = groupDatabase.getGroups();
|
|
||||||
|
|
||||||
String number = recipient.getNumber();
|
|
||||||
|
|
||||||
try {
|
|
||||||
number = Util.canonicalizeNumber(context, number);
|
|
||||||
} catch (InvalidNumberException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
GroupDatabase.GroupRecord groupRecord;
|
|
||||||
|
|
||||||
while ((groupRecord = reader.getNext()) != null) {
|
|
||||||
if (groupRecord.getMembers().contains(number) && groupRecord.isActive()) {
|
|
||||||
SignalServiceGroup group = new SignalServiceGroup(groupRecord.getId());
|
|
||||||
IncomingTextMessage incoming = new IncomingTextMessage(number, 1, time, null, Optional.of(group), 0);
|
|
||||||
IncomingIdentityUpdateMessage groupUpdate = new IncomingIdentityUpdateMessage(incoming);
|
|
||||||
|
|
||||||
smsDatabase.insertMessageInbox(groupUpdate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (threadDatabase.getThreadIdIfExistsFor(recipients) != -1) {
|
|
||||||
IncomingTextMessage incoming = new IncomingTextMessage(number, 1, time, null, Optional.<SignalServiceGroup>absent(), 0);
|
|
||||||
IncomingIdentityUpdateMessage individualUpdate = new IncomingIdentityUpdateMessage(incoming);
|
|
||||||
smsDatabase.insertMessageInbox(individualUpdate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onShouldRetryThrowable(Exception exception) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAdded() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCanceled() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,119 @@
|
|||||||
|
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;
|
||||||
|
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
|
||||||
|
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 {
|
||||||
|
Recipients recipients = RecipientFactory.getRecipientsForIds(context, recipientIds, true);
|
||||||
|
|
||||||
|
for (Recipient recipient : recipients) {
|
||||||
|
if (recipient.isGroupRecipient()) handleGroupRecipient(recipient);
|
||||||
|
else handleIndividualRecipient(recipient);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onShouldRetry(Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCanceled() {}
|
||||||
|
|
||||||
|
private void handleIndividualRecipient(Recipient recipient)
|
||||||
|
throws IOException, InvalidKeyException
|
||||||
|
{
|
||||||
|
SignalServiceProfile profile = retrieveProfile(recipient.getNumber());
|
||||||
|
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) {
|
||||||
|
IdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(context);
|
||||||
|
|
||||||
|
if (identityKeyStore.saveIdentity(new SignalProtocolAddress(recipient.getNumber(), 1), identityKey)) {
|
||||||
|
Log.w(TAG, "Deleting all sessions...");
|
||||||
|
new TextSecureSessionStore(getContext()).deleteAllSessions(recipient.getNumber());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleGroupRecipient(Recipient group)
|
||||||
|
throws IOException, InvalidKeyException
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue