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(); 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..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 @@ -30,18 +30,30 @@ 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 MemberLeft : Kind() - class EncryptionKeyPairRequest: 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() val description: String = run { when(this) { @@ -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 ecb56edf02..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(val closedGroups: List, val openGroups: List, val contacts: List, val displayName: String, val profilePicture: String?, val profileKey: ByteArray): 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 } @@ -30,7 +32,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) @@ -42,8 +44,8 @@ class ConfigurationMessage(val closedGroups: List, val openGroups: 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(val closedGroups: List, val openGroups: } } - 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 @@ -128,6 +133,8 @@ class ConfigurationMessage(val closedGroups: List, val openGroups: } } + internal constructor(): this(listOf(), listOf(), listOf(), "", null, byteArrayOf()) + override fun toProto(): SignalServiceProtos.Content? { val configurationProto = SignalServiceProtos.ConfigurationMessage.newBuilder() configurationProto.addAllClosedGroups(closedGroups.mapNotNull { it.toProto() }) 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 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 }