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