Add refresh path for PreKey queue.

This commit is contained in:
Moxie Marlinspike
2014-03-19 11:14:15 -07:00
parent 926d3c929f
commit ad5d6d5bb7
7 changed files with 148 additions and 74 deletions

View File

@@ -8,6 +8,7 @@ import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessageV2;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.service.PreKeyService;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.sms.OutgoingKeyExchangeMessage;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
@@ -121,6 +122,8 @@ public class KeyExchangeProcessorV2 extends KeyExchangeProcessor {
PreKeyRecord.delete(context, preKeyId);
}
PreKeyService.initiateRefresh(context, masterSecret);
DatabaseFactory.getIdentityDatabase(context)
.saveIdentity(masterSecret, recipientDevice.getRecipientId(), theirIdentityKey);
}

View File

@@ -0,0 +1,90 @@
package org.thoughtcrime.securesms.service;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.push.PushServiceSocketFactory;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.textsecure.crypto.IdentityKey;
import org.whispersystems.textsecure.crypto.MasterSecret;
import org.whispersystems.textsecure.crypto.PreKeyUtil;
import org.whispersystems.textsecure.crypto.ecc.Curve;
import org.whispersystems.textsecure.push.PushServiceSocket;
import org.whispersystems.textsecure.storage.PreKeyRecord;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class PreKeyService extends Service {
private static final String TAG = PreKeyService.class.getSimpleName();
public static final String REFRESH_ACTION = "org.thoughtcrime.securesms.PreKeyService.REFRESH";
private static final int PREKEY_MINIMUM = 10;
private final Executor executor = Executors.newSingleThreadExecutor();
public static void initiateRefresh(Context context, MasterSecret masterSecret) {
Intent intent = new Intent(context, PreKeyService.class);
intent.setAction(PreKeyService.REFRESH_ACTION);
intent.putExtra("master_secret", masterSecret);
context.startService(intent);
}
@Override
public int onStartCommand(Intent intent, int flats, int startId) {
if (REFRESH_ACTION.equals(intent.getAction())) {
MasterSecret masterSecret = intent.getParcelableExtra("master_secret");
executor.execute(new RefreshTask(this, masterSecret));
}
return START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private static class RefreshTask implements Runnable {
private final Context context;
private final MasterSecret masterSecret;
public RefreshTask(Context context, MasterSecret masterSecret) {
this.context = context.getApplicationContext();
this.masterSecret = masterSecret;
}
public void run() {
try {
if (!TextSecurePreferences.isPushRegistered(context)) return;
PushServiceSocket socket = PushServiceSocketFactory.create(context);
int availableKeys = socket.getAvailablePreKeys();
if (availableKeys >= PREKEY_MINIMUM) {
Log.w(TAG, "Available keys sufficient: " + availableKeys);
return;
}
List<PreKeyRecord> preKeyRecords = PreKeyUtil.generatePreKeys(context, masterSecret);
PreKeyRecord lastResortKeyRecord = PreKeyUtil.generateLastResortKey(context, masterSecret);
IdentityKey identityKey = IdentityKeyUtil.getIdentityKey(context, Curve.DJB_TYPE);
Log.w(TAG, "Registering new prekeys...");
socket.registerPreKeys(identityKey, lastResortKeyRecord, preKeyRecords);
} catch (IOException e) {
Log.w(TAG, e);
}
}
}
}

View File

@@ -68,7 +68,6 @@ public class RegistrationService extends Service {
public static final String GCM_REGISTRATION_ID = "GCMRegistrationId";
private static final long REGISTRATION_TIMEOUT_MILLIS = 120000;
private static final Object GENERATING_PREKEYS_SEMAPHOR = new Object();
private final ExecutorService executor = Executors.newSingleThreadExecutor();
private final Binder binder = new RegistrationServiceBinder();
@@ -144,27 +143,6 @@ public class RegistrationService extends Service {
registerReceiver(gcmRegistrationReceiver, filter);
}
private void initializePreKeyGenerator(final MasterSecret masterSecret) {
synchronized (GENERATING_PREKEYS_SEMAPHOR) {
if (generatingPreKeys) return;
else generatingPreKeys = true;
}
new Thread() {
public void run() {
if (PreKeyUtil.getPreKeys(RegistrationService.this, masterSecret).size() < PreKeyUtil.BATCH_SIZE) {
PreKeyUtil.generatePreKeys(RegistrationService.this, masterSecret);
PreKeyUtil.generateLastResortKey(RegistrationService.this, masterSecret);
}
synchronized (GENERATING_PREKEYS_SEMAPHOR) {
generatingPreKeys = false;
GENERATING_PREKEYS_SEMAPHOR.notifyAll();
}
}
}.start();
}
private synchronized void shutdownChallengeListener() {
if (challengeReceiver != null) {
unregisterReceiver(challengeReceiver);
@@ -195,7 +173,6 @@ public class RegistrationService extends Service {
try {
initializeGcmRegistrationListener();
initializePreKeyGenerator(masterSecret);
PushServiceSocket socket = PushServiceSocketFactory.create(this, number, password);
@@ -240,8 +217,6 @@ public class RegistrationService extends Service {
initializeChallengeListener();
initializeGcmRegistrationListener();
initializePreKeyGenerator(masterSecret);
setState(new RegistrationState(RegistrationState.STATE_CONNECTING, number));
PushServiceSocket socket = PushServiceSocketFactory.create(this, number, password);
@@ -287,7 +262,7 @@ public class RegistrationService extends Service {
{
setState(new RegistrationState(RegistrationState.STATE_GENERATING_KEYS, number));
IdentityKey identityKey = IdentityKeyUtil.getIdentityKey(this, Curve.DJB_TYPE);
List<PreKeyRecord> records = waitForPreKeys(masterSecret);
List<PreKeyRecord> records = PreKeyUtil.generatePreKeys(this, masterSecret);
PreKeyRecord lastResort = PreKeyUtil.generateLastResortKey(this, masterSecret);
socket.registerPreKeys(identityKey, lastResort, records);
@@ -333,20 +308,6 @@ public class RegistrationService extends Service {
return this.gcmRegistrationId;
}
private List<PreKeyRecord> waitForPreKeys(MasterSecret masterSecret) {
synchronized (GENERATING_PREKEYS_SEMAPHOR) {
while (generatingPreKeys) {
try {
GENERATING_PREKEYS_SEMAPHOR.wait();
} catch (InterruptedException e) {
throw new AssertionError(e);
}
}
}
return PreKeyUtil.getPreKeys(this, masterSecret);
}
private synchronized void challengeReceived(String challenge) {
this.challenge = challenge;
notifyAll();