Really really delay SMS processing until sqlcipher migration completes

Blocking the SMS job on the screen lock isn't enough, since then
the job races against the migration.

Fixes #7390
This commit is contained in:
Moxie Marlinspike 2018-02-26 14:02:12 -08:00
parent a0a9e412b4
commit 18aa202695
6 changed files with 87 additions and 4 deletions

View File

@ -33,6 +33,7 @@ import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob;
import org.thoughtcrime.securesms.jobs.GcmRefreshJob;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirementProvider;
import org.thoughtcrime.securesms.jobs.requirements.ServiceRequirementProvider;
import org.thoughtcrime.securesms.jobs.requirements.SqlCipherMigrationRequirementProvider;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
import org.thoughtcrime.securesms.service.DirectoryRefreshListener;
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
@ -121,7 +122,8 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
.withJobSerializer(new JavaJobSerializer())
.withRequirementProviders(new MasterSecretRequirementProvider(this),
new ServiceRequirementProvider(this),
new NetworkRequirementProvider(this))
new NetworkRequirementProvider(this),
new SqlCipherMigrationRequirementProvider())
.withConsumerThreads(5)
.build();
}

View File

@ -696,6 +696,10 @@ public class SmsDatabase extends MessagingDatabase {
return threadDeleted;
}
public void ensureMigration() {
databaseHelper.getWritableDatabase();
}
private boolean isDuplicate(IncomingTextMessage message, long threadId) {
SQLiteDatabase database = databaseHelper.getReadableDatabase();
Cursor cursor = database.query(TABLE_NAME, null, DATE_SENT + " = ? AND " + ADDRESS + " = ? AND " + THREAD_ID + " = ?",

View File

@ -10,9 +10,11 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
import org.thoughtcrime.securesms.jobs.requirements.SqlCipherMigrationRequirement;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.libsignal.util.guava.Optional;
@ -33,6 +35,7 @@ public class SmsReceiveJob extends ContextJob {
.withPersistence()
.withWakeLock(true)
.withRequirement(new MasterSecretRequirement(context))
.withRequirement(new SqlCipherMigrationRequirement(context))
.create());
this.pdus = pdus;
@ -43,7 +46,7 @@ public class SmsReceiveJob extends ContextJob {
public void onAdded() {}
@Override
public void onRun() {
public void onRun() throws MigrationPendingException {
Log.w(TAG, "onRun()");
Optional<IncomingTextMessage> message = assembleMessageFragments(pdus, subscriptionId);
@ -68,7 +71,7 @@ public class SmsReceiveJob extends ContextJob {
@Override
public boolean onShouldRetry(Exception exception) {
return false;
return exception instanceof MigrationPendingException;
}
private boolean isBlocked(IncomingTextMessage message) {
@ -80,8 +83,13 @@ public class SmsReceiveJob extends ContextJob {
return false;
}
private Optional<InsertResult> storeMessage(IncomingTextMessage message) {
private Optional<InsertResult> storeMessage(IncomingTextMessage message) throws MigrationPendingException {
SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
database.ensureMigration();
if (TextSecurePreferences.getNeedsSqlCipherMigration(context)) {
throw new MigrationPendingException();
}
if (message.isSecureMessage()) {
IncomingTextMessage placeholder = new IncomingTextMessage(message, "");
@ -111,4 +119,8 @@ public class SmsReceiveJob extends ContextJob {
return Optional.of(new IncomingTextMessage(messages));
}
private class MigrationPendingException extends Exception {
}
}

View File

@ -0,0 +1,31 @@
package org.thoughtcrime.securesms.jobs.requirements;
import android.content.Context;
import android.support.annotation.NonNull;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.jobqueue.dependencies.ContextDependent;
import org.whispersystems.jobqueue.requirements.Requirement;
public class SqlCipherMigrationRequirement implements Requirement, ContextDependent {
@SuppressWarnings("unused")
private static final String TAG = SqlCipherMigrationRequirement.class.getSimpleName();
private transient Context context;
public SqlCipherMigrationRequirement(@NonNull Context context) {
this.context = context;
}
@Override
public void setContext(Context context) {
this.context = context;
}
@Override
public boolean isPresent() {
return !TextSecurePreferences.getNeedsSqlCipherMigration(context);
}
}

View File

@ -0,0 +1,31 @@
package org.thoughtcrime.securesms.jobs.requirements;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.whispersystems.jobqueue.requirements.RequirementListener;
import org.whispersystems.jobqueue.requirements.RequirementProvider;
public class SqlCipherMigrationRequirementProvider implements RequirementProvider {
private RequirementListener listener;
public SqlCipherMigrationRequirementProvider() {
EventBus.getDefault().register(this);
}
@Override
public void setListener(RequirementListener listener) {
this.listener = listener;
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(SqlCipherNeedsMigrationEvent event) {
if (listener != null) listener.onRequirementStatusChanged();
}
public static class SqlCipherNeedsMigrationEvent {
}
}

View File

@ -14,7 +14,9 @@ import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.util.Pair;
import org.greenrobot.eventbus.EventBus;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.jobs.requirements.SqlCipherMigrationRequirementProvider;
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference;
import java.io.IOException;
@ -127,6 +129,7 @@ public class TextSecurePreferences {
public static void setNeedsSqlCipherMigration(@NonNull Context context, boolean value) {
setBooleanPreference(context, NEEDS_SQLCIPHER_MIGRATION, value);
EventBus.getDefault().post(new SqlCipherMigrationRequirementProvider.SqlCipherNeedsMigrationEvent());
}
public static boolean getNeedsSqlCipherMigration(@NonNull Context context) {