From b72e5c4c6a7a44f97f4da5a0acd1224c5088099d Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 4 Sep 2019 11:11:48 +1000 Subject: [PATCH] Fix group chat restoration --- .../securesms/loki/LokiGroupChatPoller.kt | 54 ++++++++++++++++--- .../securesms/loki/LokiMessageDatabase.kt | 2 + 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt b/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt index 3e12e669d3..a5c57e31f9 100644 --- a/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt +++ b/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt @@ -4,8 +4,12 @@ import android.content.Context import android.os.Handler import android.util.Log import org.thoughtcrime.securesms.crypto.IdentityKeyUtil +import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.jobs.PushDecryptJob +import org.thoughtcrime.securesms.recipients.Recipient +import org.thoughtcrime.securesms.sms.OutgoingTextMessage +import org.thoughtcrime.securesms.util.GroupUtil import org.thoughtcrime.securesms.util.TextSecurePreferences import org.whispersystems.libsignal.util.guava.Optional import org.whispersystems.signalservice.api.messages.SignalServiceContent @@ -14,20 +18,25 @@ import org.whispersystems.signalservice.api.messages.SignalServiceGroup import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.loki.api.LokiGroupChat import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI +import org.whispersystems.signalservice.loki.api.LokiGroupMessage class LokiGroupChatPoller(private val context: Context, private val group: LokiGroupChat) { private val handler = Handler() private var hasStarted = false + // region Convenience + private val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context) + private val api: LokiGroupChatAPI get() = { - val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context) val lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(context) val lokiUserDatabase = DatabaseFactory.getLokiUserDatabase(context) val userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(context).privateKey.serialize() LokiGroupChatAPI(userHexEncodedPublicKey, userPrivateKey, lokiAPIDatabase, lokiUserDatabase) }() + // endregion + // region Tasks private val pollForNewMessagesTask = object : Runnable { override fun run() { @@ -51,13 +60,17 @@ class LokiGroupChatPoller(private val context: Context, private val group: LokiG handler.postDelayed(this, pollForModerationPermissionInterval) } } + // endregion + // region Settings companion object { private val pollForNewMessagesInterval: Long = 4 * 1000 private val pollForDeletedMessagesInterval: Long = 20 * 1000 private val pollForModerationPermissionInterval: Long = 10 * 60 * 1000 } + // endregion + // region Lifecycle fun startIfNeeded() { if (hasStarted) return pollForNewMessagesTask.run() @@ -72,16 +85,40 @@ class LokiGroupChatPoller(private val context: Context, private val group: LokiG handler.removeCallbacks(pollForModerationPermissionTask) hasStarted = false } + // endregion + // region Polling private fun pollForNewMessages() { + fun processIncomingMessage(message: LokiGroupMessage) { + val id = group.id.toByteArray() + val x1 = SignalServiceGroup(SignalServiceGroup.Type.UPDATE, id, null, null, null) + val x2 = SignalServiceDataMessage(message.timestamp, x1, null, message.body) + val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})" + val x3 = SignalServiceContent(x2, senderDisplayName, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false) + PushDecryptJob(context).handleTextMessage(x3, x2, Optional.absent(), Optional.of(message.serverID)) + } + fun processOutgoingMessage(message: LokiGroupMessage) { + val messageServerID = message.serverID ?: return + val lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context) + val isDuplicate = lokiMessageDatabase.getMessageID(messageServerID) != null + if (isDuplicate) { return } + val id = group.id.toByteArray() + val smsDatabase = DatabaseFactory.getSmsDatabase(context) + val recipient = Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(id, false)), false) + val signalMessage = OutgoingTextMessage(recipient, message.body, 0, 0) + val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient) + val messageID = smsDatabase.insertMessageOutbox(threadID, signalMessage, false, System.currentTimeMillis(), null) + smsDatabase.markAsSent(messageID, true) + smsDatabase.markUnidentified(messageID, false) + lokiMessageDatabase.setServerID(messageID, messageServerID) + } api.getMessages(group.serverID, group.server).success { messages -> - messages.reversed().map { message -> - val id = group.id.toByteArray() - val x1 = SignalServiceGroup(SignalServiceGroup.Type.UPDATE, id, null, null, null) - val x2 = SignalServiceDataMessage(message.timestamp, x1, null, message.body) - val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})" - val x3 = SignalServiceContent(x2, senderDisplayName, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false) - PushDecryptJob(context).handleTextMessage(x3, x2, Optional.absent(), Optional.of(message.serverID)) + messages.reversed().forEach { message -> + if (message.hexEncodedPublicKey != userHexEncodedPublicKey) { + processIncomingMessage(message) + } else { + processOutgoingMessage(message) + } } }.fail { Log.d("Loki", "Failed to get messages for group chat with ID: ${group.serverID} on server: ${group.server}.") @@ -109,4 +146,5 @@ class LokiGroupChatPoller(private val context: Context, private val group: LokiG lokiAPIDatabase.setIsModerator(group.serverID, group.server, isModerator) } } + // endregion } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/LokiMessageDatabase.kt b/src/org/thoughtcrime/securesms/loki/LokiMessageDatabase.kt index 11429c1e84..b0459cee98 100644 --- a/src/org/thoughtcrime/securesms/loki/LokiMessageDatabase.kt +++ b/src/org/thoughtcrime/securesms/loki/LokiMessageDatabase.kt @@ -18,6 +18,8 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab @JvmStatic val createTableCommand = "CREATE TABLE $tableName ($messageID INTEGER PRIMARY KEY, $serverID INTEGER DEFAULT 0, $friendRequestStatus INTEGER DEFAULT 0);" } + // TODO: Move the server ID stuff to LokiAPIDatabase? + fun getServerID(messageID: Long): Long? { val database = databaseHelper.readableDatabase return database.get(tableName, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) { cursor ->