From 18aa202695fdda06642f071c4481a6a99d37de9c Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Mon, 26 Feb 2018 14:02:12 -0800 Subject: [PATCH] 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 --- .../securesms/ApplicationContext.java | 4 ++- .../securesms/database/SmsDatabase.java | 4 +++ .../securesms/jobs/SmsReceiveJob.java | 18 +++++++++-- .../SqlCipherMigrationRequirement.java | 31 +++++++++++++++++++ ...SqlCipherMigrationRequirementProvider.java | 31 +++++++++++++++++++ .../securesms/util/TextSecurePreferences.java | 3 ++ 6 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 src/org/thoughtcrime/securesms/jobs/requirements/SqlCipherMigrationRequirement.java create mode 100644 src/org/thoughtcrime/securesms/jobs/requirements/SqlCipherMigrationRequirementProvider.java diff --git a/src/org/thoughtcrime/securesms/ApplicationContext.java b/src/org/thoughtcrime/securesms/ApplicationContext.java index 7d482bf05f..3071f56e24 100644 --- a/src/org/thoughtcrime/securesms/ApplicationContext.java +++ b/src/org/thoughtcrime/securesms/ApplicationContext.java @@ -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(); } diff --git a/src/org/thoughtcrime/securesms/database/SmsDatabase.java b/src/org/thoughtcrime/securesms/database/SmsDatabase.java index 9d442abb6e..2b926e74fd 100644 --- a/src/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -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 + " = ?", diff --git a/src/org/thoughtcrime/securesms/jobs/SmsReceiveJob.java b/src/org/thoughtcrime/securesms/jobs/SmsReceiveJob.java index f623e5c1a9..bc2ac532e8 100644 --- a/src/org/thoughtcrime/securesms/jobs/SmsReceiveJob.java +++ b/src/org/thoughtcrime/securesms/jobs/SmsReceiveJob.java @@ -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 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 storeMessage(IncomingTextMessage message) { + private Optional 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 { + + } } diff --git a/src/org/thoughtcrime/securesms/jobs/requirements/SqlCipherMigrationRequirement.java b/src/org/thoughtcrime/securesms/jobs/requirements/SqlCipherMigrationRequirement.java new file mode 100644 index 0000000000..ab5898631e --- /dev/null +++ b/src/org/thoughtcrime/securesms/jobs/requirements/SqlCipherMigrationRequirement.java @@ -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); + } +} diff --git a/src/org/thoughtcrime/securesms/jobs/requirements/SqlCipherMigrationRequirementProvider.java b/src/org/thoughtcrime/securesms/jobs/requirements/SqlCipherMigrationRequirementProvider.java new file mode 100644 index 0000000000..08c9e576a9 --- /dev/null +++ b/src/org/thoughtcrime/securesms/jobs/requirements/SqlCipherMigrationRequirementProvider.java @@ -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 { + + } +} diff --git a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java index 2ef51d7211..2a1f318160 100644 --- a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java +++ b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java @@ -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) {