Replace rather than insert into push db on duplicate incoming.

Combined with the switch to server acked messages, this will
prevent the race condition that occurred when an incoming message
showed up at exactly the moment the app updated.

It'd be great if we could just do REPLACE INTO, but it's too
late to add a UNIQUE() constraint. =(

Fixes #2287
Closes #3029

// FREEBIE
This commit is contained in:
Moxie Marlinspike 2015-04-21 13:04:00 -07:00
parent a330f6f689
commit 7b3bd2fbf7
2 changed files with 43 additions and 9 deletions

View File

@ -58,7 +58,7 @@ public class DatabaseUpgradeActivity extends BaseActivity {
public static final int ASYMMETRIC_MASTER_SECRET_FIX_VERSION = 73;
public static final int NO_V1_VERSION = 83;
public static final int SIGNED_PREKEY_VERSION = 83;
public static final int NO_DECRYPT_QUEUE_VERSION = 84;
public static final int NO_DECRYPT_QUEUE_VERSION = 113;
private static final SortedSet<Integer> UPGRADE_VERSIONS = new TreeSet<Integer>() {{
add(NO_MORE_KEY_EXCHANGE_PREFIX_VERSION);

View File

@ -3,10 +3,13 @@ package org.thoughtcrime.securesms.database;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.support.annotation.NonNull;
import android.util.Log;
import org.thoughtcrime.securesms.util.Base64;
import org.whispersystems.libaxolotl.util.guava.Optional;
import org.whispersystems.textsecure.api.messages.TextSecureEnvelope;
import java.io.IOException;
@ -30,15 +33,21 @@ public class PushDatabase extends Database {
super(context, databaseHelper);
}
public long insert(TextSecureEnvelope envelope) {
ContentValues values = new ContentValues();
values.put(TYPE, envelope.getType());
values.put(SOURCE, envelope.getSource());
values.put(DEVICE_ID, envelope.getSourceDevice());
values.put(BODY, Base64.encodeBytes(envelope.getMessage()));
values.put(TIMESTAMP, envelope.getTimestamp());
public long insert(@NonNull TextSecureEnvelope envelope) {
Optional<Long> messageId = find(envelope);
return databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, values);
if (messageId.isPresent()) {
return messageId.get();
} else {
ContentValues values = new ContentValues();
values.put(TYPE, envelope.getType());
values.put(SOURCE, envelope.getSource());
values.put(DEVICE_ID, envelope.getSourceDevice());
values.put(BODY, Base64.encodeBytes(envelope.getMessage()));
values.put(TIMESTAMP, envelope.getTimestamp());
return databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, values);
}
}
public TextSecureEnvelope get(long id) throws NoSuchMessageException {
@ -80,6 +89,31 @@ public class PushDatabase extends Database {
return new Reader(cursor);
}
private Optional<Long> find(TextSecureEnvelope envelope) {
SQLiteDatabase database = databaseHelper.getReadableDatabase();
Cursor cursor = null;
try {
cursor = database.query(TABLE_NAME, null, TYPE + " = ? AND " + SOURCE + " = ? AND " +
DEVICE_ID + " = ? AND " + BODY + " = ? AND " +
TIMESTAMP + " = ?" ,
new String[] {String.valueOf(envelope.getType()),
envelope.getSource(),
String.valueOf(envelope.getSourceDevice()),
Base64.encodeBytes(envelope.getMessage()),
String.valueOf(envelope.getTimestamp())},
null, null, null);
if (cursor != null && cursor.moveToFirst()) {
return Optional.of(cursor.getLong(cursor.getColumnIndexOrThrow(ID)));
} else {
return Optional.absent();
}
} finally {
if (cursor != null) cursor.close();
}
}
public static class Reader {
private final Cursor cursor;