Add pre-alpha receive support for remote delete.

This commit is contained in:
Greyson Parrelli
2020-04-15 14:56:58 -04:00
parent 456bcf3d57
commit 6ecd3b59fd
29 changed files with 595 additions and 82 deletions

View File

@@ -50,6 +50,9 @@ public abstract class MessagingDatabase extends Database implements MmsSmsColumn
public abstract void markAsSent(long messageId, boolean secure);
public abstract void markUnidentified(long messageId, boolean unidentified);
public abstract void markAsSending(long messageId);
public abstract void markAsRemoteDelete(long messageId);
final int getInsecureMessagesSentForThread(long threadId) {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
String[] projection = new String[]{"COUNT(*)"};

View File

@@ -168,7 +168,8 @@ public class MmsDatabase extends MessagingDatabase {
VIEW_ONCE + " INTEGER DEFAULT 0, " +
REACTIONS + " BLOB DEFAULT NULL, " +
REACTIONS_UNREAD + " INTEGER DEFAULT 0, " +
REACTIONS_LAST_SEEN + " INTEGER DEFAULT -1);";
REACTIONS_LAST_SEEN + " INTEGER DEFAULT -1, " +
REMOTE_DELETED + " INTEGER DEFAULT 0);";
public static final String[] CREATE_INDEXS = {
"CREATE INDEX IF NOT EXISTS mms_thread_id_index ON " + TABLE_NAME + " (" + THREAD_ID + ");",
@@ -193,6 +194,7 @@ public class MmsDatabase extends MessagingDatabase {
DELIVERY_RECEIPT_COUNT, READ_RECEIPT_COUNT, MISMATCHED_IDENTITIES, NETWORK_FAILURE, SUBSCRIPTION_ID,
EXPIRES_IN, EXPIRE_STARTED, NOTIFIED, QUOTE_ID, QUOTE_AUTHOR, QUOTE_BODY, QUOTE_ATTACHMENT, QUOTE_MISSING,
SHARED_CONTACTS, LINK_PREVIEWS, UNIDENTIFIED, VIEW_ONCE, REACTIONS, REACTIONS_UNREAD, REACTIONS_LAST_SEEN,
REMOTE_DELETED,
"json_group_array(json_object(" +
"'" + AttachmentDatabase.ROW_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.ROW_ID + ", " +
"'" + AttachmentDatabase.UNIQUE_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.UNIQUE_ID + ", " +
@@ -473,6 +475,7 @@ public class MmsDatabase extends MessagingDatabase {
notifyConversationListeners(threadId);
}
@Override
public void markAsSending(long messageId) {
long threadId = getThreadIdForMessage(messageId);
updateMailboxBitmask(messageId, Types.BASE_TYPE_MASK, Types.BASE_SENDING_TYPE, Optional.of(threadId));
@@ -492,6 +495,29 @@ public class MmsDatabase extends MessagingDatabase {
notifyConversationListeners(threadId);
}
@Override
public void markAsRemoteDelete(long messageId) {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(REMOTE_DELETED, 1);
values.putNull(BODY);
values.putNull(QUOTE_BODY);
values.putNull(QUOTE_AUTHOR);
values.putNull(QUOTE_ATTACHMENT);
values.putNull(QUOTE_ID);
values.putNull(LINK_PREVIEWS);
values.putNull(SHARED_CONTACTS);
values.putNull(REACTIONS);
db.update(TABLE_NAME, values, ID_WHERE, new String[] { String.valueOf(messageId) });
DatabaseFactory.getAttachmentDatabase(context).deleteAttachmentsForMessage(messageId);
long threadId = getThreadIdForMessage(messageId);
DatabaseFactory.getThreadDatabase(context).update(threadId, false);
notifyConversationListeners(threadId);
}
public void markDownloadState(long messageId, long state) {
SQLiteDatabase database = databaseHelper.getWritableDatabase();
ContentValues contentValues = new ContentValues();
@@ -1506,7 +1532,8 @@ public class MmsDatabase extends MessagingDatabase {
message.getSharedContacts(),
message.getLinkPreviews(),
false,
Collections.emptyList());
Collections.emptyList(),
false);
}
}
@@ -1597,6 +1624,7 @@ public class MmsDatabase extends MessagingDatabase {
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRE_STARTED));
boolean unidentified = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.UNIDENTIFIED)) == 1;
boolean isViewOnce = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.VIEW_ONCE)) == 1;
boolean remoteDelete = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.REMOTE_DELETED)) == 1;
List<ReactionRecord> reactions = parseReactions(cursor);
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
@@ -1618,7 +1646,8 @@ public class MmsDatabase extends MessagingDatabase {
addressDeviceId, dateSent, dateReceived, dateServer, deliveryReceiptCount,
threadId, body, slideDeck, partCount, box, mismatches,
networkFailures, subscriptionId, expiresIn, expireStarted,
isViewOnce, readReceiptCount, quote, contacts, previews, unidentified, reactions);
isViewOnce, readReceiptCount, quote, contacts, previews, unidentified, reactions,
remoteDelete);
}
private List<IdentityKeyMismatch> getMismatchedIdentities(String document) {

View File

@@ -24,6 +24,7 @@ public interface MmsSmsColumns {
public static final String REACTIONS = "reactions";
public static final String REACTIONS_UNREAD = "reactions_unread";
public static final String REACTIONS_LAST_SEEN = "reactions_last_seen";
public static final String REMOTE_DELETED = "remote_deleted";
public static class Types {
protected static final long TOTAL_MASK = 0xFFFFFFFF;

View File

@@ -28,6 +28,7 @@ import net.sqlcipher.database.SQLiteQueryBuilder;
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.whispersystems.libsignal.util.Pair;
@@ -87,7 +88,8 @@ public class MmsSmsDatabase extends Database {
MmsSmsColumns.READ,
MmsSmsColumns.REACTIONS,
MmsSmsColumns.REACTIONS_UNREAD,
MmsSmsColumns.REACTIONS_LAST_SEEN};
MmsSmsColumns.REACTIONS_LAST_SEEN,
MmsSmsColumns.REMOTE_DELETED};
public MmsSmsDatabase(Context context, SQLCipherOpenHelper databaseHelper) {
super(context, databaseHelper);
@@ -395,7 +397,8 @@ public class MmsSmsDatabase extends Database {
MmsDatabase.REACTIONS,
MmsSmsColumns.REACTIONS_UNREAD,
MmsSmsColumns.REACTIONS_LAST_SEEN,
MmsSmsColumns.DATE_SERVER };
MmsSmsColumns.DATE_SERVER,
MmsSmsColumns.REMOTE_DELETED };
String[] smsProjection = {SmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT,
SmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
@@ -426,7 +429,8 @@ public class MmsSmsDatabase extends Database {
MmsDatabase.REACTIONS,
MmsSmsColumns.REACTIONS_UNREAD,
MmsSmsColumns.REACTIONS_LAST_SEEN,
MmsSmsColumns.DATE_SERVER };
MmsSmsColumns.DATE_SERVER,
MmsSmsColumns.REMOTE_DELETED };
SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
@@ -478,6 +482,7 @@ public class MmsSmsDatabase extends Database {
mmsColumnsPresent.add(MmsDatabase.REACTIONS);
mmsColumnsPresent.add(MmsDatabase.REACTIONS_UNREAD);
mmsColumnsPresent.add(MmsDatabase.REACTIONS_LAST_SEEN);
mmsColumnsPresent.add(MmsDatabase.REMOTE_DELETED);
Set<String> smsColumnsPresent = new HashSet<>();
smsColumnsPresent.add(MmsSmsColumns.ID);
@@ -503,6 +508,7 @@ public class MmsSmsDatabase extends Database {
smsColumnsPresent.add(SmsDatabase.REACTIONS);
smsColumnsPresent.add(SmsDatabase.REACTIONS_UNREAD);
smsColumnsPresent.add(SmsDatabase.REACTIONS_LAST_SEEN);
smsColumnsPresent.add(MmsDatabase.REMOTE_DELETED);
@SuppressWarnings("deprecation")
String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(TRANSPORT, mmsProjection, mmsColumnsPresent, 4, MMS_TRANSPORT, selection, null, MmsDatabase.TABLE_NAME + "." + MmsDatabase.ID, null);

View File

@@ -48,6 +48,7 @@ import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.util.JsonUtils;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
import java.io.IOException;
import java.security.SecureRandom;
@@ -103,7 +104,8 @@ public class SmsDatabase extends MessagingDatabase {
UNIDENTIFIED + " INTEGER DEFAULT 0, " +
REACTIONS + " BLOB DEFAULT NULL, " +
REACTIONS_UNREAD + " INTEGER DEFAULT 0, " +
REACTIONS_LAST_SEEN + " INTEGER DEFAULT -1);";
REACTIONS_LAST_SEEN + " INTEGER DEFAULT -1, " +
REMOTE_DELETED + " INTEGER DEFAULT 0);";
public static final String[] CREATE_INDEXS = {
"CREATE INDEX IF NOT EXISTS sms_thread_id_index ON " + TABLE_NAME + " (" + THREAD_ID + ");",
@@ -124,7 +126,8 @@ public class SmsDatabase extends MessagingDatabase {
PROTOCOL, READ, STATUS, TYPE,
REPLY_PATH_PRESENT, SUBJECT, BODY, SERVICE_CENTER, DELIVERY_RECEIPT_COUNT,
MISMATCHED_IDENTITIES, SUBSCRIPTION_ID, EXPIRES_IN, EXPIRE_STARTED,
NOTIFIED, READ_RECEIPT_COUNT, UNIDENTIFIED, REACTIONS, REACTIONS_UNREAD, REACTIONS_LAST_SEEN
NOTIFIED, READ_RECEIPT_COUNT, UNIDENTIFIED, REACTIONS, REACTIONS_UNREAD, REACTIONS_LAST_SEEN,
REMOTE_DELETED
};
private final String OUTGOING_INSECURE_MESSAGE_CLAUSE = "(" + TYPE + " & " + Types.BASE_TYPE_MASK + ") = " + Types.BASE_SENT_TYPE + " AND NOT (" + TYPE + " & " + Types.SECURE_MESSAGE_BIT + ")";
@@ -314,6 +317,7 @@ public class SmsDatabase extends MessagingDatabase {
updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.BASE_SENT_TYPE | (isSecure ? Types.PUSH_MESSAGE_BIT | Types.SECURE_MESSAGE_BIT : 0));
}
@Override
public void markAsSending(long id) {
updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.BASE_SENDING_TYPE);
}
@@ -322,6 +326,21 @@ public class SmsDatabase extends MessagingDatabase {
updateTypeBitmask(id, Types.TOTAL_MASK, Types.MISSED_CALL_TYPE);
}
@Override
public void markAsRemoteDelete(long id) {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(REMOTE_DELETED, 1);
values.putNull(BODY);
db.update(TABLE_NAME, values, ID_WHERE, new String[] { String.valueOf(id) });
long threadId = getThreadIdForMessage(id);
DatabaseFactory.getThreadDatabase(context).update(threadId, false);
notifyConversationListeners(threadId);
}
@Override
public void markUnidentified(long id, boolean unidentified) {
ContentValues contentValues = new ContentValues(1);
@@ -913,7 +932,8 @@ public class SmsDatabase extends MessagingDatabase {
System.currentTimeMillis(),
0,
false,
Collections.emptyList());
Collections.emptyList(),
false);
}
}
@@ -955,6 +975,7 @@ public class SmsDatabase extends MessagingDatabase {
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.EXPIRE_STARTED));
String body = cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.BODY));
boolean unidentified = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.UNIDENTIFIED)) == 1;
boolean remoteDelete = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.REMOTE_DELETED)) == 1;
List<ReactionRecord> reactions = parseReactions(cursor);
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
@@ -970,7 +991,7 @@ public class SmsDatabase extends MessagingDatabase {
dateSent, dateReceived, dateServer, deliveryReceiptCount, type,
threadId, status, mismatches, subscriptionId,
expiresIn, expireStarted,
readReceiptCount, unidentified, reactions);
readReceiptCount, unidentified, reactions, remoteDelete);
}
private List<IdentityKeyMismatch> getMismatches(String document) {

View File

@@ -773,8 +773,10 @@ public class ThreadDatabase extends Database {
return Extra.forMessageRequest();
}
if (record.isMms() && ((MmsMessageRecord) record).isViewOnce()) {
return Extra.forRevealable();
if (record.isViewOnce()) {
return Extra.forViewOnce();
} else if (record.isRemoteDelete()) {
return Extra.forRemoteDelete();
} else if (record.isMms() && ((MmsMessageRecord) record).getSlideDeck().getStickerSlide() != null) {
return Extra.forSticker();
} else if (record.isMms() && ((MmsMessageRecord) record).getSlideDeck().getSlides().size() > 1) {
@@ -899,43 +901,50 @@ public class ThreadDatabase extends Database {
@JsonProperty private final boolean isRevealable;
@JsonProperty private final boolean isSticker;
@JsonProperty private final boolean isAlbum;
@JsonProperty private final boolean isRemoteDelete;
@JsonProperty private final boolean isMessageRequestAccepted;
@JsonProperty private final String groupAddedBy;
public Extra(@JsonProperty("isRevealable") boolean isRevealable,
@JsonProperty("isSticker") boolean isSticker,
@JsonProperty("isAlbum") boolean isAlbum,
@JsonProperty("isRemoteDelete") boolean isRemoteDelete,
@JsonProperty("isMessageRequestAccepted") boolean isMessageRequestAccepted,
@JsonProperty("groupAddedBy") String groupAddedBy)
{
this.isRevealable = isRevealable;
this.isSticker = isSticker;
this.isAlbum = isAlbum;
this.isRemoteDelete = isRemoteDelete;
this.isMessageRequestAccepted = isMessageRequestAccepted;
this.groupAddedBy = groupAddedBy;
}
public static @NonNull Extra forRevealable() {
return new Extra(true, false, false, true, null);
public static @NonNull Extra forViewOnce() {
return new Extra(true, false, false, false, true, null);
}
public static @NonNull Extra forSticker() {
return new Extra(false, true, false, true, null);
return new Extra(false, true, false, false, true, null);
}
public static @NonNull Extra forAlbum() {
return new Extra(false, false, true, true, null);
return new Extra(false, false, true, false, true, null);
}
public static @NonNull Extra forRemoteDelete() {
return new Extra(false, false, false, true, true, null);
}
public static @NonNull Extra forMessageRequest() {
return new Extra(false, false, false, false, null);
return new Extra(false, false, false, false, false, null);
}
public static @NonNull Extra forGroupMessageRequest(RecipientId recipientId) {
return new Extra(false, false, false, false, recipientId.serialize());
return new Extra(false, false, false, false, false, recipientId.serialize());
}
public boolean isRevealable() {
public boolean isViewOnce() {
return isRevealable;
}
@@ -947,6 +956,10 @@ public class ThreadDatabase extends Database {
return isAlbum;
}
public boolean isRemoteDelete() {
return isRemoteDelete;
}
public boolean isMessageRequestAccepted() {
return isMessageRequestAccepted;
}

View File

@@ -129,8 +129,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
private static final int ATTACHMENT_CDN_NUMBER = 57;
private static final int JOB_INPUT_DATA = 58;
private static final int SERVER_TIMESTAMP = 59;
private static final int REMOTE_DELETE = 60;
private static final int DATABASE_VERSION = 59;
private static final int DATABASE_VERSION = 60;
private static final String DATABASE_NAME = "signal.db";
private final Context context;
@@ -882,6 +883,11 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
db.execSQL("CREATE INDEX IF NOT EXISTS mms_date_server_index ON mms (date_server)");
}
if (oldVersion < REMOTE_DELETE) {
db.execSQL("ALTER TABLE sms ADD COLUMN remote_deleted INTEGER DEFAULT 0");
db.execSQL("ALTER TABLE mms ADD COLUMN remote_deleted INTEGER DEFAULT 0");
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();

View File

@@ -70,12 +70,13 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
@NonNull List<Contact> contacts,
@NonNull List<LinkPreview> linkPreviews,
boolean unidentified,
@NonNull List<ReactionRecord> reactions)
@NonNull List<ReactionRecord> reactions,
boolean remoteDelete)
{
super(id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent,
dateReceived, dateServer, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox, mismatches, failures,
subscriptionId, expiresIn, expireStarted, viewOnce, slideDeck,
readReceiptCount, quote, contacts, linkPreviews, unidentified, reactions);
readReceiptCount, quote, contacts, linkPreviews, unidentified, reactions, remoteDelete);
this.partCount = partCount;
}

View File

@@ -55,6 +55,7 @@ public abstract class MessageRecord extends DisplayRecord {
private final boolean unidentified;
private final List<ReactionRecord> reactions;
private final long serverTimestamp;
private final boolean remoteDelete;
MessageRecord(long id, String body, Recipient conversationRecipient,
Recipient individualRecipient, int recipientDeviceId,
@@ -64,7 +65,7 @@ public abstract class MessageRecord extends DisplayRecord {
List<NetworkFailure> networkFailures,
int subscriptionId, long expiresIn, long expireStarted,
int readReceiptCount, boolean unidentified,
@NonNull List<ReactionRecord> reactions)
@NonNull List<ReactionRecord> reactions, boolean remoteDelete)
{
super(body, conversationRecipient, dateSent, dateReceived,
threadId, deliveryStatus, deliveryReceiptCount, type, readReceiptCount);
@@ -79,6 +80,7 @@ public abstract class MessageRecord extends DisplayRecord {
this.unidentified = unidentified;
this.reactions = reactions;
this.serverTimestamp = dateServer;
this.remoteDelete = remoteDelete;
}
public abstract boolean isMms();
@@ -259,6 +261,10 @@ public abstract class MessageRecord extends DisplayRecord {
return false;
}
public boolean isRemoteDelete() {
return remoteDelete;
}
public @NonNull List<ReactionRecord> getReactions() {
return reactions;
}

View File

@@ -33,9 +33,9 @@ public abstract class MmsMessageRecord extends MessageRecord {
@NonNull SlideDeck slideDeck, int readReceiptCount,
@Nullable Quote quote, @NonNull List<Contact> contacts,
@NonNull List<LinkPreview> linkPreviews, boolean unidentified,
@NonNull List<ReactionRecord> reactions)
@NonNull List<ReactionRecord> reactions, boolean remoteDelete)
{
super(id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent, dateReceived, dateServer, threadId, deliveryStatus, deliveryReceiptCount, type, mismatches, networkFailures, subscriptionId, expiresIn, expireStarted, readReceiptCount, unidentified, reactions);
super(id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent, dateReceived, dateServer, threadId, deliveryStatus, deliveryReceiptCount, type, mismatches, networkFailures, subscriptionId, expiresIn, expireStarted, readReceiptCount, unidentified, reactions, remoteDelete);
this.slideDeck = slideDeck;
this.quote = quote;

View File

@@ -58,7 +58,7 @@ public class NotificationMmsMessageRecord extends MmsMessageRecord {
dateSent, dateReceived, -1, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox,
new LinkedList<>(), new LinkedList<>(), subscriptionId,
0, 0, false, slideDeck, readReceiptCount, null, Collections.emptyList(), Collections.emptyList(), false,
Collections.emptyList());
Collections.emptyList(), false);
this.contentLocation = contentLocation;
this.messageSize = messageSize;

View File

@@ -49,12 +49,12 @@ public class SmsMessageRecord extends MessageRecord {
int status, List<IdentityKeyMismatch> mismatches,
int subscriptionId, long expiresIn, long expireStarted,
int readReceiptCount, boolean unidentified,
@NonNull List<ReactionRecord> reactions)
@NonNull List<ReactionRecord> reactions, boolean remoteDelete)
{
super(id, body, recipient, individualRecipient, recipientDeviceId,
dateSent, dateReceived, dateServer, threadId, status, deliveryReceiptCount, type,
mismatches, new LinkedList<>(), subscriptionId,
expiresIn, expireStarted, readReceiptCount, unidentified, reactions);
expiresIn, expireStarted, readReceiptCount, unidentified, reactions, remoteDelete);
}
public long getType() {

View File

@@ -127,8 +127,10 @@ public class ThreadRecord extends DisplayRecord {
if (TextUtils.isEmpty(getBody())) {
if (extra != null && extra.isSticker()) {
return new SpannableString(emphasisAdded(context.getString(R.string.ThreadRecord_sticker)));
} else if (extra != null && extra.isRevealable()) {
} else if (extra != null && extra.isViewOnce()) {
return new SpannableString(emphasisAdded(getViewOnceDescription(context, contentType)));
} else if (extra != null && extra.isRemoteDelete()) {
return new SpannableString(emphasisAdded(context.getString(R.string.ThreadRecord_this_message_was_deleted)));
} else {
return new SpannableString(emphasisAdded(context.getString(R.string.ThreadRecord_media_message)));
}