Skip to content

Commit

Permalink
Ignore duplicate signal messages
Browse files Browse the repository at this point in the history
Fixes #5579

// FREEBIE
  • Loading branch information
moxie0 committed Jan 22, 2017
1 parent 47aa797 commit 7e51d61
Show file tree
Hide file tree
Showing 9 changed files with 193 additions and 100 deletions.
Expand Up @@ -35,6 +35,7 @@
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.util.LRUCache;
import org.whispersystems.libsignal.InvalidMessageException;
import org.whispersystems.libsignal.util.guava.Optional;

import java.lang.ref.SoftReference;
import java.util.Collections;
Expand Down Expand Up @@ -78,8 +79,8 @@ public long insertMessageOutbox(MasterSecretUnion masterSecret, long threadId,
return insertMessageOutbox(threadId, message, type, forceSms, timestamp);
}

public Pair<Long, Long> insertMessageInbox(@NonNull MasterSecretUnion masterSecret,
@NonNull IncomingTextMessage message)
public Optional<InsertResult> insertMessageInbox(@NonNull MasterSecretUnion masterSecret,
@NonNull IncomingTextMessage message)
{
if (masterSecret.getMasterSecret().isPresent()) {
return insertMessageInbox(masterSecret.getMasterSecret().get(), message);
Expand All @@ -88,8 +89,8 @@ public Pair<Long, Long> insertMessageInbox(@NonNull MasterSecretUnion masterSecr
}
}

private Pair<Long, Long> insertMessageInbox(@NonNull MasterSecret masterSecret,
@NonNull IncomingTextMessage message)
private Optional<InsertResult> insertMessageInbox(@NonNull MasterSecret masterSecret,
@NonNull IncomingTextMessage message)
{
long type = Types.BASE_INBOX_TYPE | Types.ENCRYPTION_SYMMETRIC_BIT;

Expand All @@ -98,8 +99,8 @@ private Pair<Long, Long> insertMessageInbox(@NonNull MasterSecret masterSecret,
return insertMessageInbox(message, type);
}

private Pair<Long, Long> insertMessageInbox(@NonNull AsymmetricMasterSecret masterSecret,
@NonNull IncomingTextMessage message)
private Optional<InsertResult> insertMessageInbox(@NonNull AsymmetricMasterSecret masterSecret,
@NonNull IncomingTextMessage message)
{
long type = Types.BASE_INBOX_TYPE | Types.ENCRYPTION_ASYMMETRIC_BIT;

Expand Down
17 changes: 17 additions & 0 deletions src/org/thoughtcrime/securesms/database/MessagingDatabase.java
Expand Up @@ -235,4 +235,21 @@ public ExpirationInfo getExpirationInfo() {
}
}

public static class InsertResult {
private final long messageId;
private final long threadId;

public InsertResult(long messageId, long threadId) {
this.messageId = messageId;
this.threadId = threadId;
}

public long getMessageId() {
return messageId;
}

public long getThreadId() {
return threadId;
}
}
}
41 changes: 30 additions & 11 deletions src/org/thoughtcrime/securesms/database/MmsDatabase.java
Expand Up @@ -693,10 +693,10 @@ public long copyMessageInbox(MasterSecret masterSecret, long messageId) throws M
}
}

private Pair<Long, Long> insertMessageInbox(MasterSecretUnion masterSecret,
IncomingMediaMessage retrieved,
String contentLocation,
long threadId, long mailbox)
private Optional<InsertResult> insertMessageInbox(MasterSecretUnion masterSecret,
IncomingMediaMessage retrieved,
String contentLocation,
long threadId, long mailbox)
throws MmsException
{
if (threadId == -1 || retrieved.isGroupMessage()) {
Expand Down Expand Up @@ -729,6 +729,11 @@ private Pair<Long, Long> insertMessageInbox(MasterSecretUnion masterSecret,
contentValues.put(DATE_SENT, contentValues.getAsLong(DATE_RECEIVED));
}

if (retrieved.isPushMessage() && isDuplicate(retrieved, threadId)) {
Log.w(TAG, "Ignoring duplicate media message (" + retrieved.getSentTimeMillis() + ")");
return Optional.absent();
}

long messageId = insertMediaMessage(masterSecret, retrieved.getAddresses(),
retrieved.getBody(), retrieved.getAttachments(),
contentValues);
Expand All @@ -741,12 +746,12 @@ private Pair<Long, Long> insertMessageInbox(MasterSecretUnion masterSecret,
notifyConversationListeners(threadId);
jobManager.add(new TrimThreadJob(context, threadId));

return new Pair<>(messageId, threadId);
return Optional.of(new InsertResult(messageId, threadId));
}

public Pair<Long, Long> insertMessageInbox(MasterSecretUnion masterSecret,
IncomingMediaMessage retrieved,
String contentLocation, long threadId)
public Optional<InsertResult> insertMessageInbox(MasterSecretUnion masterSecret,
IncomingMediaMessage retrieved,
String contentLocation, long threadId)
throws MmsException
{
long type = Types.BASE_INBOX_TYPE;
Expand All @@ -768,9 +773,9 @@ public Pair<Long, Long> insertMessageInbox(MasterSecretUnion masterSecret,
return insertMessageInbox(masterSecret, retrieved, contentLocation, threadId, type);
}

public Pair<Long, Long> insertSecureDecryptedMessageInbox(MasterSecretUnion masterSecret,
IncomingMediaMessage retrieved,
long threadId)
public Optional<InsertResult> insertSecureDecryptedMessageInbox(MasterSecretUnion masterSecret,
IncomingMediaMessage retrieved,
long threadId)
throws MmsException
{
long type = Types.BASE_INBOX_TYPE | Types.SECURE_MESSAGE_BIT;
Expand Down Expand Up @@ -990,6 +995,20 @@ public void deleteThread(long threadId) {
deleteThreads(singleThreadSet);
}

private boolean isDuplicate(IncomingMediaMessage message, long threadId) {
SQLiteDatabase database = databaseHelper.getReadableDatabase();
Cursor cursor = database.query(TABLE_NAME, null, DATE_SENT + " = ? AND " + ADDRESS + " = ? AND " + THREAD_ID + " = ?",
new String[]{String.valueOf(message.getSentTimeMillis()), message.getAddresses().getFrom(), String.valueOf(threadId)},
null, null, null, "1");

try {
return cursor != null && cursor.moveToFirst();
} finally {
if (cursor != null) cursor.close();
}
}


/*package*/ void deleteThreads(Set<Long> threadIds) {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
String where = "";
Expand Down
46 changes: 33 additions & 13 deletions src/org/thoughtcrime/securesms/database/SmsDatabase.java
Expand Up @@ -42,6 +42,7 @@
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.util.JsonUtils;
import org.whispersystems.jobqueue.JobManager;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.util.InvalidNumberException;

import java.io.IOException;
Expand Down Expand Up @@ -482,7 +483,7 @@ public Pair<Long, Long> copyMessageInbox(long messageId) {
return new Pair<>(messageId, threadId);
}

protected Pair<Long, Long> insertMessageInbox(IncomingTextMessage message, long type) {
protected Optional<InsertResult> insertMessageInbox(IncomingTextMessage message, long type) {
if (message.isJoined()) {
type = (type & (Types.TOTAL_MASK - Types.BASE_TYPE_MASK)) | Types.JOINED_TYPE;
} else if (message.isPreKeyBundle()) {
Expand Down Expand Up @@ -546,24 +547,29 @@ protected Pair<Long, Long> insertMessageInbox(IncomingTextMessage message, long
values.put(TYPE, type);
values.put(THREAD_ID, threadId);

SQLiteDatabase db = databaseHelper.getWritableDatabase();
long messageId = db.insert(TABLE_NAME, null, values);
if (message.isPush() && isDuplicate(message, threadId)) {
Log.w(TAG, "Duplicate message (" + message.getSentTimestampMillis() + "), ignoring...");
return Optional.absent();
} else {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
long messageId = db.insert(TABLE_NAME, null, values);

if (unread) {
DatabaseFactory.getThreadDatabase(context).setUnread(threadId);
}
if (unread) {
DatabaseFactory.getThreadDatabase(context).setUnread(threadId);
}

if (!message.isIdentityUpdate()) {
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
}
if (!message.isIdentityUpdate()) {
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
}

notifyConversationListeners(threadId);
jobManager.add(new TrimThreadJob(context, threadId));
notifyConversationListeners(threadId);
jobManager.add(new TrimThreadJob(context, threadId));

return new Pair<>(messageId, threadId);
return Optional.of(new InsertResult(messageId, threadId));
}
}

public Pair<Long, Long> insertMessageInbox(IncomingTextMessage message) {
public Optional<InsertResult> insertMessageInbox(IncomingTextMessage message) {
return insertMessageInbox(message, Types.BASE_INBOX_TYPE);
}

Expand Down Expand Up @@ -653,6 +659,19 @@ public boolean deleteMessage(long messageId) {
return threadDeleted;
}

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 + " = ?",
new String[]{String.valueOf(message.getSentTimestampMillis()), message.getSender(), String.valueOf(threadId)},
null, null, null, "1");

try {
return cursor != null && cursor.moveToFirst();
} finally {
if (cursor != null) cursor.close();
}
}

/*package */void deleteThread(long threadId) {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
db.delete(TABLE_NAME, THREAD_ID + " = ?", new String[] {threadId+""});
Expand Down Expand Up @@ -817,4 +836,5 @@ public void close() {
cursor.close();
}
}

}
12 changes: 8 additions & 4 deletions src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java
Expand Up @@ -5,7 +5,6 @@
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import android.util.Pair;

import com.google.protobuf.ByteString;

Expand All @@ -15,6 +14,7 @@
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
import org.thoughtcrime.securesms.jobs.AvatarDownloadJob;
import org.thoughtcrime.securesms.jobs.PushGroupUpdateJob;
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
Expand Down Expand Up @@ -216,10 +216,14 @@ private static Long handleGroupLeave(@NonNull Context context,
IncomingTextMessage incoming = new IncomingTextMessage(envelope.getSource(), envelope.getSourceDevice(), envelope.getTimestamp(), body, Optional.of(group), 0);
IncomingGroupMessage groupMessage = new IncomingGroupMessage(incoming, storage, body);

Pair<Long, Long> messageAndThreadId = smsDatabase.insertMessageInbox(masterSecret, groupMessage);
MessageNotifier.updateNotification(context, masterSecret.getMasterSecret().orNull(), messageAndThreadId.second);
Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(masterSecret, groupMessage);

return messageAndThreadId.second;
if (insertResult.isPresent()) {
MessageNotifier.updateNotification(context, masterSecret.getMasterSecret().orNull(), insertResult.get().getThreadId());
return insertResult.get().getThreadId();
} else {
return null;
}
}
} catch (MmsException e) {
Log.w(TAG, e);
Expand Down
13 changes: 8 additions & 5 deletions src/org/thoughtcrime/securesms/jobs/MmsDownloadJob.java
Expand Up @@ -11,6 +11,7 @@
import org.thoughtcrime.securesms.crypto.MasterSecretUnion;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
import org.thoughtcrime.securesms.mms.ApnUnavailableException;
Expand Down Expand Up @@ -194,12 +195,14 @@ private void storeRetrievedMms(MasterSecret masterSecret, String contentLocation



IncomingMediaMessage message = new IncomingMediaMessage(from, to, cc, body, retrieved.getDate() * 1000L, attachments, subscriptionId, 0, false);
IncomingMediaMessage message = new IncomingMediaMessage(from, to, cc, body, retrieved.getDate() * 1000L, attachments, subscriptionId, 0, false);
Optional<InsertResult> insertResult = database.insertMessageInbox(new MasterSecretUnion(masterSecret),
message, contentLocation, threadId);

Pair<Long, Long> messageAndThreadId = database.insertMessageInbox(new MasterSecretUnion(masterSecret),
message, contentLocation, threadId);
database.delete(messageId);
MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second);
if (insertResult.isPresent()) {
database.delete(messageId);
MessageNotifier.updateNotification(context, masterSecret, insertResult.get().getThreadId());
}
}

private void handleDownloadError(MasterSecret masterSecret, long messageId, long threadId,
Expand Down

0 comments on commit 7e51d61

Please sign in to comment.