diff --git a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt index 93ad37e323..51835fc88e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt @@ -182,7 +182,8 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper) } override fun getServerHashForMessage(messageID: Long): String? { - TODO("Not yet implemented") + val messageDB = DatabaseFactory.getLokiMessageDatabase(context) + return messageDB.getMessageServerHash(messageID) } override fun getDatabaseAttachment(attachmentId: Long): DatabaseAttachment? { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/LokiMessageDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/LokiMessageDatabase.kt index c36c197cbb..85b345e3f6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/LokiMessageDatabase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/LokiMessageDatabase.kt @@ -12,12 +12,14 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab private val messageIDTable = "loki_message_friend_request_database" private val messageThreadMappingTable = "loki_message_thread_mapping_database" private val errorMessageTable = "loki_error_message_database" + private val messageHashTable = "loki_message_hash_database" private val messageID = "message_id" private val serverID = "server_id" private val friendRequestStatus = "friend_request_status" private val threadID = "thread_id" private val errorMessage = "error_message" private val messageType = "message_type" + private val serverHash = "server_hash" @JvmStatic val createMessageIDTableCommand = "CREATE TABLE $messageIDTable ($messageID INTEGER PRIMARY KEY, $serverID INTEGER DEFAULT 0, $friendRequestStatus INTEGER DEFAULT 0);" @JvmStatic @@ -28,6 +30,8 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab val updateMessageIDTableForType = "ALTER TABLE $messageIDTable ADD COLUMN $messageType INTEGER DEFAULT 0; ALTER TABLE $messageIDTable ADD CONSTRAINT PK_$messageIDTable PRIMARY KEY ($messageID, $serverID);" @JvmStatic val updateMessageMappingTable = "ALTER TABLE $messageThreadMappingTable ADD COLUMN $serverID INTEGER DEFAULT 0; ALTER TABLE $messageThreadMappingTable ADD CONSTRAINT PK_$messageThreadMappingTable PRIMARY KEY ($messageID, $serverID);" + @JvmStatic + val createMessageHashTableCommand = "CREATE TABLE IF NOT EXISTS $messageHashTable ($messageID INTEGER PRIMARY KEY, $serverHash STRING);" const val SMS_TYPE = 0 const val MMS_TYPE = 1 @@ -150,4 +154,19 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab database.endTransaction() } } + + fun getMessageServerHash(messageID: Long): String? { + val database = databaseHelper.readableDatabase + return database.get(messageHashTable, "${Companion.messageID} = ?", arrayOf(messageID.toString())) { cursor -> + cursor.getString(serverHash) + } + } + + fun setMessageServerHash(messageID: Long, serverHash: String) { + val database = databaseHelper.writableDatabase + val contentValues = ContentValues(2) + contentValues.put(Companion.messageID, messageID) + contentValues.put(Companion.serverHash, serverHash) + database.insertOrUpdate(messageHashTable, contentValues, "${Companion.messageID} = ?", arrayOf(messageID.toString())) + } } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index fe9327a13e..66332bed60 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -358,6 +358,10 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, } } + override fun setMessageServerHash(messageID: Long, serverHash: String) { + DatabaseFactory.getLokiMessageDatabase(context).setMessageServerHash(messageID, serverHash) + } + override fun getGroup(groupID: String): GroupRecord? { val group = DatabaseFactory.getGroupDatabase(context).getGroup(groupID) return if (group.isPresent) { group.get() } else null diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java index 106528ee25..a7fa86cb5a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java @@ -59,6 +59,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { private static final int lokiV25 = 46; private static final int lokiV26 = 47; private static final int lokiV27 = 48; + private static final int lokiV28 = 49; // Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes private static final int DATABASE_VERSION = lokiV27; @@ -123,6 +124,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { db.execSQL(LokiMessageDatabase.getCreateMessageIDTableCommand()); db.execSQL(LokiMessageDatabase.getCreateMessageToThreadMappingTableCommand()); db.execSQL(LokiMessageDatabase.getCreateErrorMessageTableCommand()); + db.execSQL(LokiMessageDatabase.getCreateMessageHashTableCommand()); db.execSQL(LokiThreadDatabase.getCreateSessionResetTableCommand()); db.execSQL(LokiThreadDatabase.getCreatePublicChatTableCommand()); db.execSQL(LokiUserDatabase.getCreateDisplayNameTableCommand()); @@ -302,6 +304,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { db.execSQL(RecipientDatabase.getCreateNotificationTypeCommand()); } + if (oldVersion < lokiV28) { + db.execSQL(LokiMessageDatabase.getCreateMessageHashTableCommand()); + } + db.setTransactionSuccessful(); } finally { db.endTransaction(); diff --git a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt index bc7324d21a..3c8e0c7123 100644 --- a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt +++ b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt @@ -93,6 +93,7 @@ interface StorageProtocol { fun markAsSent(timestamp: Long, author: String) fun markUnidentified(timestamp: Long, author: String) fun setErrorMessage(timestamp: Long, author: String, error: Exception) + fun setMessageServerHash(messageID: Long, serverHash: String) // Closed Groups fun getGroup(groupID: String): GroupRecord? diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/Message.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/Message.kt index 56779795ea..d201daa98d 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/Message.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/Message.kt @@ -13,6 +13,7 @@ abstract class Message { var sender: String? = null var groupPublicKey: String? = null var openGroupServerMessageID: Long? = null + var serverHash: String? = null open val ttl: Long = 14 * 24 * 60 * 60 * 1000 open val isSelfSendValid: Boolean = false diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt index 4758525abb..aa78074ed5 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt @@ -161,6 +161,8 @@ object MessageSender { if (destination is Destination.Contact && message is VisibleMessage && !isSelfSend) { SnodeModule.shared.broadcaster.broadcast("messageSent", message.sentTimestamp!!) } + val hash = it["hash"] as? String + message.serverHash = hash handleSuccessfulMessageSend(message, destination, isSyncMessage) var shouldNotify = (message is VisibleMessage && !isSyncMessage) /* @@ -259,6 +261,12 @@ object MessageSender { storage.updateSentTimestamp(messageID, message.isMediaMessage(), openGroupSentTimestamp, message.threadID!!) message.sentTimestamp = openGroupSentTimestamp } + // When the sync message is successfully sent, the hash value of this TSOutgoingMessage + // will be replaced by the hash value of the sync message. Since the hash value of the + // real message has no use when we delete a message. It is OK to let it be. + message.serverHash?.let { + storage.setMessageServerHash(messageID, it) + } // Track the open group server message ID if (message.openGroupServerMessageID != null && destination is Destination.OpenGroupV2) { val encoded = GroupUtil.getEncodedOpenGroupID("${destination.server}.${destination.room}".toByteArray())