From 4628f27d9ff11f5fef00032691733ba08d02dd71 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Mon, 15 Mar 2021 13:14:45 +1100 Subject: [PATCH 1/5] fix error handling --- .../sending_receiving/MessageSender.kt | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) 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 d54fdc6f15..39a0237000 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 @@ -76,21 +76,21 @@ object MessageSender { // Set the timestamp, sender and recipient message.sentTimestamp ?: run { message.sentTimestamp = System.currentTimeMillis() } /* Visible messages will already have their sent timestamp set */ message.sender = userPublicKey + val isSelfSend = (message.recipient == userPublicKey) + // Set the failure handler (need it here already for precondition failure handling) + fun handleFailure(error: Exception) { + handleFailedMessageSend(message, error) + if (destination is Destination.Contact && message is VisibleMessage && !isSelfSend) { + SnodeConfiguration.shared.broadcaster.broadcast("messageFailed", message.sentTimestamp!!) + } + deferred.reject(error) + } try { when (destination) { is Destination.Contact -> message.recipient = destination.publicKey is Destination.ClosedGroup -> message.recipient = destination.groupPublicKey is Destination.OpenGroup -> throw preconditionFailure } - val isSelfSend = (message.recipient == userPublicKey) - // Set the failure handler (need it here already for precondition failure handling) - fun handleFailure(error: Exception) { - handleFailedMessageSend(message, error) - if (destination is Destination.Contact && message is VisibleMessage && !isSelfSend) { - SnodeConfiguration.shared.broadcaster.broadcast("messageFailed", message.sentTimestamp!!) - } - deferred.reject(error) - } // Validate the message if (!message.isValid()) { throw Error.InvalidMessage } // Stop here if this is a self-send, unless it's: @@ -183,15 +183,14 @@ object MessageSender { errorCount += 1 if (errorCount != promiseCount) { return@fail } // Only error out if all promises failed handleFailure(it) - deferred.reject(it) } } }.fail { Log.d("Loki", "Couldn't send message due to error: $it.") - deferred.reject(it) + handleFailure(it) } } catch (exception: Exception) { - deferred.reject(exception) + handleFailure(exception) } return promise } From b786f5894c7779972a2a1056036c9768d068801c Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Mon, 15 Mar 2021 14:56:05 +1100 Subject: [PATCH 2/5] fix configuration message deserialising crash --- .../messages/control/ConfigurationMessage.kt | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ConfigurationMessage.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ConfigurationMessage.kt index ecb56edf02..e33ab11b3a 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ConfigurationMessage.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ConfigurationMessage.kt @@ -14,7 +14,7 @@ import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded import org.session.libsignal.service.loki.utilities.toHexString import org.session.libsignal.utilities.Hex -class ConfigurationMessage(val closedGroups: List, val openGroups: List, val contacts: List, val displayName: String, val profilePicture: String?, val profileKey: ByteArray): ControlMessage() { +class ConfigurationMessage(): ControlMessage() { class ClosedGroup(val publicKey: String, val name: String, val encryptionKeyPair: ECKeyPair, val members: List, val admins: List) { val isValid: Boolean get() = members.isNotEmpty() && admins.isNotEmpty() @@ -30,7 +30,7 @@ class ConfigurationMessage(val closedGroups: List, val openGroups: val name = proto.name val encryptionKeyPairAsProto = proto.encryptionKeyPair val encryptionKeyPair = ECKeyPair(DjbECPublicKey(encryptionKeyPairAsProto.publicKey.toByteArray().removing05PrefixIfNeeded()), - DjbECPrivateKey(encryptionKeyPairAsProto.privateKey.toByteArray())) + DjbECPrivateKey(encryptionKeyPairAsProto.privateKey.toByteArray())) val members = proto.membersList.map { it.toByteArray().toHexString() } val admins = proto.adminsList.map { it.toByteArray().toHexString() } return ClosedGroup(publicKey, name, encryptionKeyPair, members, admins) @@ -85,6 +85,13 @@ class ConfigurationMessage(val closedGroups: List, val openGroups: override val ttl: Long = 4 * 24 * 60 * 60 * 1000 override val isSelfSendValid: Boolean = true + var closedGroups: List = listOf() + var openGroups: List = listOf() + var contacts: List = listOf() + var displayName: String = "" + var profilePicture: String? = null + var profileKey: ByteArray = byteArrayOf() + companion object { fun getCurrent(contacts: List): ConfigurationMessage? { @@ -128,6 +135,15 @@ class ConfigurationMessage(val closedGroups: List, val openGroups: } } + internal constructor(closedGroups: List, openGroups: List, contacts: List, displayName: String, profilePicture: String?, profileKey: ByteArray): this() { + this.closedGroups = closedGroups + this.openGroups = openGroups + this.contacts = contacts + this.displayName = displayName + this.profilePicture = profilePicture + this.profileKey = profileKey + } + override fun toProto(): SignalServiceProtos.Content? { val configurationProto = SignalServiceProtos.ConfigurationMessage.newBuilder() configurationProto.addAllClosedGroups(closedGroups.mapNotNull { it.toProto() }) From d2843b2cef416a7f286397db76cebfa5b03e62d9 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Mon, 15 Mar 2021 14:56:46 +1100 Subject: [PATCH 3/5] fix removing jobs in database --- .../securesms/database/helpers/SQLCipherOpenHelper.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 e86543ae8f..88d8c679f3 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 @@ -255,8 +255,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { "SmsSentJob", "SmsReceiveJob", "PushGroupUpdateJob", - "ResetThreadSessionJob", - "SendDeliveryReceiptJob"); + "ResetThreadSessionJob"); } if (oldVersion < lokiV22) { @@ -269,7 +268,8 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { "TypingSendJob", "AttachmentUploadJob", "RequestGroupInfoJob", - "ClosedGroupUpdateMessageSendJobV2"); + "ClosedGroupUpdateMessageSendJobV2", + "SendDeliveryReceiptJob"); } db.setTransactionSuccessful(); From 424aee5fb352e0f9e856cf2a01ffd98606bce430 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Mon, 15 Mar 2021 15:43:05 +1100 Subject: [PATCH 4/5] fix possible serialising crash & refactor --- .../loki/protocol/MultiDeviceProtocol.kt | 4 +-- .../messaging/messages/Destination.kt | 23 ++++--------- .../control/ClosedGroupControlMessage.kt | 32 +++++++++++++------ .../messages/control/ConfigurationMessage.kt | 31 +++++++----------- .../MessageReceiverHandler.kt | 4 +-- 5 files changed, 43 insertions(+), 51 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt index 81e137171a..69dfc70126 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt @@ -79,8 +79,8 @@ object MultiDeviceProtocol { closedGroupUpdate.publicKey = ByteString.copyFrom(Hex.fromStringCondensed(closedGroup.publicKey)) closedGroupUpdate.name = closedGroup.name val encryptionKeyPair = SignalServiceProtos.KeyPair.newBuilder() - encryptionKeyPair.publicKey = ByteString.copyFrom(closedGroup.encryptionKeyPair.publicKey.serialize().removing05PrefixIfNeeded()) - encryptionKeyPair.privateKey = ByteString.copyFrom(closedGroup.encryptionKeyPair.privateKey.serialize()) + encryptionKeyPair.publicKey = ByteString.copyFrom(closedGroup.encryptionKeyPair!!.publicKey.serialize().removing05PrefixIfNeeded()) + encryptionKeyPair.privateKey = ByteString.copyFrom(closedGroup.encryptionKeyPair!!.privateKey.serialize()) closedGroupUpdate.encryptionKeyPair = encryptionKeyPair.build() closedGroupUpdate.addAllMembers(closedGroup.members.map { ByteString.copyFrom(Hex.fromStringCondensed(it)) }) closedGroupUpdate.addAllAdmins(closedGroup.admins.map { ByteString.copyFrom(Hex.fromStringCondensed(it)) }) diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt index 47e48de38d..ef389b08b0 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt @@ -7,25 +7,14 @@ import org.session.libsignal.service.loki.utilities.toHexString sealed class Destination { - class Contact() : Destination() { - var publicKey: String = "" - internal constructor(publicKey: String): this() { - this.publicKey = publicKey - } + class Contact(var publicKey: String) : Destination() { + internal constructor(): this("") } - class ClosedGroup() : Destination() { - var groupPublicKey: String = "" - internal constructor(groupPublicKey: String): this() { - this.groupPublicKey = groupPublicKey - } + class ClosedGroup(var groupPublicKey: String) : Destination() { + internal constructor(): this("") } - class OpenGroup() : Destination() { - var channel: Long = 0 - var server: String = "" - internal constructor(channel: Long, server: String): this() { - this.channel = channel - this.server = server - } + class OpenGroup(var channel: Long, var server: String) : Destination() { + internal constructor(): this(0, "") } companion object { diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupControlMessage.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupControlMessage.kt index bad3ad566f..ea483fa41f 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupControlMessage.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupControlMessage.kt @@ -30,16 +30,28 @@ class ClosedGroupControlMessage() : ControlMessage() { // Kind enum sealed class Kind { - class New(val publicKey: ByteString, val name: String, val encryptionKeyPair: ECKeyPair, val members: List, val admins: List) : Kind() + class New(var publicKey: ByteString, var name: String, var encryptionKeyPair: ECKeyPair?, var members: List, var admins: List) : Kind() { + internal constructor(): this(ByteString.EMPTY, "", null, listOf(), listOf()) + } /// - Note: Deprecated in favor of more explicit group updates. - class Update(val name: String, val members: List) : Kind() + class Update(var name: String, var members: List) : Kind() { + internal constructor(): this("", listOf()) + } /// An encryption key pair encrypted for each member individually. /// /// - Note: `publicKey` is only set when an encryption key pair is sent in a one-to-one context (i.e. not in a group). - class EncryptionKeyPair(val publicKey: ByteString?, val wrappers: Collection) : Kind() - class NameChange(val name: String) : Kind() - class MembersAdded(val members: List) : Kind() - class MembersRemoved( val members: List) : Kind() + class EncryptionKeyPair(var publicKey: ByteString?, var wrappers: Collection) : Kind() { + internal constructor(): this(null, listOf()) + } + class NameChange(var name: String) : Kind() { + internal constructor(): this("") + } + class MembersAdded(var members: List) : Kind() { + internal constructor(): this(listOf()) + } + class MembersRemoved(var members: List) : Kind() { + internal constructor(): this(listOf()) + } class MemberLeft : Kind() class EncryptionKeyPairRequest: Kind() @@ -118,8 +130,8 @@ class ClosedGroupControlMessage() : ControlMessage() { val kind = kind ?: return false return when(kind) { is Kind.New -> { - !kind.publicKey.isEmpty && kind.name.isNotEmpty() && kind.encryptionKeyPair.publicKey != null - && kind.encryptionKeyPair.privateKey != null && kind.members.isNotEmpty() && kind.admins.isNotEmpty() + !kind.publicKey.isEmpty && kind.name.isNotEmpty() && kind.encryptionKeyPair!!.publicKey != null + && kind.encryptionKeyPair!!.privateKey != null && kind.members.isNotEmpty() && kind.admins.isNotEmpty() } is Kind.Update -> kind.name.isNotEmpty() is Kind.EncryptionKeyPair -> true @@ -145,8 +157,8 @@ class ClosedGroupControlMessage() : ControlMessage() { closedGroupControlMessage.publicKey = kind.publicKey closedGroupControlMessage.name = kind.name val encryptionKeyPair = SignalServiceProtos.KeyPair.newBuilder() - encryptionKeyPair.publicKey = ByteString.copyFrom(kind.encryptionKeyPair.publicKey.serialize().removing05PrefixIfNeeded()) - encryptionKeyPair.privateKey = ByteString.copyFrom(kind.encryptionKeyPair.privateKey.serialize()) + encryptionKeyPair.publicKey = ByteString.copyFrom(kind.encryptionKeyPair!!.publicKey.serialize().removing05PrefixIfNeeded()) + encryptionKeyPair.privateKey = ByteString.copyFrom(kind.encryptionKeyPair!!.privateKey.serialize()) closedGroupControlMessage.encryptionKeyPair = encryptionKeyPair.build() closedGroupControlMessage.addAllMembers(kind.members) closedGroupControlMessage.addAllAdmins(kind.admins) diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ConfigurationMessage.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ConfigurationMessage.kt index e33ab11b3a..fe06cc6c01 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ConfigurationMessage.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ConfigurationMessage.kt @@ -14,11 +14,13 @@ import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded import org.session.libsignal.service.loki.utilities.toHexString import org.session.libsignal.utilities.Hex -class ConfigurationMessage(): ControlMessage() { +class ConfigurationMessage(var closedGroups: List, var openGroups: List, var contacts: List, var displayName: String, var profilePicture: String?, var profileKey: ByteArray): ControlMessage() { - class ClosedGroup(val publicKey: String, val name: String, val encryptionKeyPair: ECKeyPair, val members: List, val admins: List) { + class ClosedGroup(var publicKey: String, var name: String, var encryptionKeyPair: ECKeyPair?, var members: List, var admins: List) { val isValid: Boolean get() = members.isNotEmpty() && admins.isNotEmpty() + internal constructor(): this("", "", null, listOf(), listOf()) + override fun toString(): String { return name } @@ -42,8 +44,8 @@ class ConfigurationMessage(): ControlMessage() { result.publicKey = ByteString.copyFrom(Hex.fromStringCondensed(publicKey)) result.name = name val encryptionKeyPairAsProto = SignalServiceProtos.KeyPair.newBuilder() - encryptionKeyPairAsProto.publicKey = ByteString.copyFrom(encryptionKeyPair.publicKey.serialize().removing05PrefixIfNeeded()) - encryptionKeyPairAsProto.privateKey = ByteString.copyFrom(encryptionKeyPair.privateKey.serialize()) + encryptionKeyPairAsProto.publicKey = ByteString.copyFrom(encryptionKeyPair!!.publicKey.serialize().removing05PrefixIfNeeded()) + encryptionKeyPairAsProto.privateKey = ByteString.copyFrom(encryptionKeyPair!!.privateKey.serialize()) result.encryptionKeyPair = encryptionKeyPairAsProto.build() result.addAllMembers(members.map { ByteString.copyFrom(Hex.fromStringCondensed(it)) }) result.addAllAdmins(admins.map { ByteString.copyFrom(Hex.fromStringCondensed(it)) }) @@ -51,7 +53,10 @@ class ConfigurationMessage(): ControlMessage() { } } - class Contact(val publicKey: String, val name: String, val profilePicture: String?, val profileKey: ByteArray?) { + class Contact(var publicKey: String, var name: String, var profilePicture: String?, var profileKey: ByteArray?) { + + internal constructor(): this("", "", null, null) + companion object { fun fromProto(proto: SignalServiceProtos.ConfigurationMessage.Contact): Contact? { if (!proto.hasName() || !proto.hasProfileKey()) return null @@ -85,13 +90,6 @@ class ConfigurationMessage(): ControlMessage() { override val ttl: Long = 4 * 24 * 60 * 60 * 1000 override val isSelfSendValid: Boolean = true - var closedGroups: List = listOf() - var openGroups: List = listOf() - var contacts: List = listOf() - var displayName: String = "" - var profilePicture: String? = null - var profileKey: ByteArray = byteArrayOf() - companion object { fun getCurrent(contacts: List): ConfigurationMessage? { @@ -135,14 +133,7 @@ class ConfigurationMessage(): ControlMessage() { } } - internal constructor(closedGroups: List, openGroups: List, contacts: List, displayName: String, profilePicture: String?, profileKey: ByteArray): this() { - this.closedGroups = closedGroups - this.openGroups = openGroups - this.contacts = contacts - this.displayName = displayName - this.profilePicture = profilePicture - this.profileKey = profileKey - } + internal constructor(): this(listOf(), listOf(), listOf(), "", null, byteArrayOf()) override fun toProto(): SignalServiceProtos.Content? { val configurationProto = SignalServiceProtos.ConfigurationMessage.newBuilder() diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageReceiverHandler.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageReceiverHandler.kt index 114b0ba326..c1bfee205f 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageReceiverHandler.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageReceiverHandler.kt @@ -110,7 +110,7 @@ private fun MessageReceiver.handleConfigurationMessage(message: ConfigurationMes val allClosedGroupPublicKeys = storage.getAllClosedGroupPublicKeys() for (closeGroup in message.closedGroups) { if (allClosedGroupPublicKeys.contains(closeGroup.publicKey)) continue - handleNewClosedGroup(message.sender!!, message.sentTimestamp!!, closeGroup.publicKey, closeGroup.name, closeGroup.encryptionKeyPair, closeGroup.members, closeGroup.admins, message.sentTimestamp!!) + handleNewClosedGroup(message.sender!!, message.sentTimestamp!!, closeGroup.publicKey, closeGroup.name, closeGroup.encryptionKeyPair!!, closeGroup.members, closeGroup.admins, message.sentTimestamp!!) } val allOpenGroups = storage.getAllOpenGroups().map { it.value.server } for (openGroup in message.openGroups) { @@ -222,7 +222,7 @@ private fun MessageReceiver.handleNewClosedGroup(message: ClosedGroupControlMess val groupPublicKey = kind.publicKey.toByteArray().toHexString() val members = kind.members.map { it.toByteArray().toHexString() } val admins = kind.admins.map { it.toByteArray().toHexString() } - handleNewClosedGroup(message.sender!!, message.sentTimestamp!!, groupPublicKey, kind.name, kind.encryptionKeyPair, members, admins, message.sentTimestamp!!) + handleNewClosedGroup(message.sender!!, message.sentTimestamp!!, groupPublicKey, kind.name, kind.encryptionKeyPair!!, members, admins, message.sentTimestamp!!) } // Parameter @sender:String is just for inserting incoming info message From 3cb20c92508da9da8584656e24de5214e913f1d1 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Mon, 15 Mar 2021 16:14:49 +1100 Subject: [PATCH 5/5] minor fix --- .../messaging/messages/control/ClosedGroupControlMessage.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupControlMessage.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupControlMessage.kt index ea483fa41f..8179865208 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupControlMessage.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupControlMessage.kt @@ -52,8 +52,8 @@ class ClosedGroupControlMessage() : ControlMessage() { class MembersRemoved(var members: List) : Kind() { internal constructor(): this(listOf()) } - class MemberLeft : Kind() - class EncryptionKeyPairRequest: Kind() + class MemberLeft() : Kind() + class EncryptionKeyPairRequest(): Kind() val description: String = run { when(this) {