Merge pull request #477 from RyanRory/refactor-sending-fix

The Refactor: Fix sending crashes
This commit is contained in:
Niels Andriesse 2021-03-16 08:57:23 +11:00 committed by GitHub
commit 16076fe40a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 61 additions and 54 deletions

View File

@ -255,8 +255,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
"SmsSentJob", "SmsSentJob",
"SmsReceiveJob", "SmsReceiveJob",
"PushGroupUpdateJob", "PushGroupUpdateJob",
"ResetThreadSessionJob", "ResetThreadSessionJob");
"SendDeliveryReceiptJob");
} }
if (oldVersion < lokiV22) { if (oldVersion < lokiV22) {
@ -269,7 +268,8 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
"TypingSendJob", "TypingSendJob",
"AttachmentUploadJob", "AttachmentUploadJob",
"RequestGroupInfoJob", "RequestGroupInfoJob",
"ClosedGroupUpdateMessageSendJobV2"); "ClosedGroupUpdateMessageSendJobV2",
"SendDeliveryReceiptJob");
} }
db.setTransactionSuccessful(); db.setTransactionSuccessful();

View File

@ -79,8 +79,8 @@ object MultiDeviceProtocol {
closedGroupUpdate.publicKey = ByteString.copyFrom(Hex.fromStringCondensed(closedGroup.publicKey)) closedGroupUpdate.publicKey = ByteString.copyFrom(Hex.fromStringCondensed(closedGroup.publicKey))
closedGroupUpdate.name = closedGroup.name closedGroupUpdate.name = closedGroup.name
val encryptionKeyPair = SignalServiceProtos.KeyPair.newBuilder() val encryptionKeyPair = SignalServiceProtos.KeyPair.newBuilder()
encryptionKeyPair.publicKey = ByteString.copyFrom(closedGroup.encryptionKeyPair.publicKey.serialize().removing05PrefixIfNeeded()) encryptionKeyPair.publicKey = ByteString.copyFrom(closedGroup.encryptionKeyPair!!.publicKey.serialize().removing05PrefixIfNeeded())
encryptionKeyPair.privateKey = ByteString.copyFrom(closedGroup.encryptionKeyPair.privateKey.serialize()) encryptionKeyPair.privateKey = ByteString.copyFrom(closedGroup.encryptionKeyPair!!.privateKey.serialize())
closedGroupUpdate.encryptionKeyPair = encryptionKeyPair.build() closedGroupUpdate.encryptionKeyPair = encryptionKeyPair.build()
closedGroupUpdate.addAllMembers(closedGroup.members.map { ByteString.copyFrom(Hex.fromStringCondensed(it)) }) closedGroupUpdate.addAllMembers(closedGroup.members.map { ByteString.copyFrom(Hex.fromStringCondensed(it)) })
closedGroupUpdate.addAllAdmins(closedGroup.admins.map { ByteString.copyFrom(Hex.fromStringCondensed(it)) }) closedGroupUpdate.addAllAdmins(closedGroup.admins.map { ByteString.copyFrom(Hex.fromStringCondensed(it)) })

View File

@ -7,25 +7,14 @@ import org.session.libsignal.service.loki.utilities.toHexString
sealed class Destination { sealed class Destination {
class Contact() : Destination() { class Contact(var publicKey: String) : Destination() {
var publicKey: String = "" internal constructor(): this("")
internal constructor(publicKey: String): this() {
this.publicKey = publicKey
} }
class ClosedGroup(var groupPublicKey: String) : Destination() {
internal constructor(): this("")
} }
class ClosedGroup() : Destination() { class OpenGroup(var channel: Long, var server: String) : Destination() {
var groupPublicKey: String = "" internal constructor(): this(0, "")
internal constructor(groupPublicKey: String): this() {
this.groupPublicKey = groupPublicKey
}
}
class OpenGroup() : Destination() {
var channel: Long = 0
var server: String = ""
internal constructor(channel: Long, server: String): this() {
this.channel = channel
this.server = server
}
} }
companion object { companion object {

View File

@ -30,18 +30,30 @@ class ClosedGroupControlMessage() : ControlMessage() {
// Kind enum // Kind enum
sealed class Kind { sealed class Kind {
class New(val publicKey: ByteString, val name: String, val encryptionKeyPair: ECKeyPair, val members: List<ByteString>, val admins: List<ByteString>) : Kind() class New(var publicKey: ByteString, var name: String, var encryptionKeyPair: ECKeyPair?, var members: List<ByteString>, var admins: List<ByteString>) : Kind() {
internal constructor(): this(ByteString.EMPTY, "", null, listOf(), listOf())
}
/// - Note: Deprecated in favor of more explicit group updates. /// - Note: Deprecated in favor of more explicit group updates.
class Update(val name: String, val members: List<ByteString>) : Kind() class Update(var name: String, var members: List<ByteString>) : Kind() {
internal constructor(): this("", listOf())
}
/// An encryption key pair encrypted for each member individually. /// 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). /// - 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<KeyPairWrapper>) : Kind() class EncryptionKeyPair(var publicKey: ByteString?, var wrappers: Collection<KeyPairWrapper>) : Kind() {
class NameChange(val name: String) : Kind() internal constructor(): this(null, listOf())
class MembersAdded(val members: List<ByteString>) : Kind() }
class MembersRemoved( val members: List<ByteString>) : Kind() class NameChange(var name: String) : Kind() {
class MemberLeft : Kind() internal constructor(): this("")
class EncryptionKeyPairRequest: Kind() }
class MembersAdded(var members: List<ByteString>) : Kind() {
internal constructor(): this(listOf())
}
class MembersRemoved(var members: List<ByteString>) : Kind() {
internal constructor(): this(listOf())
}
class MemberLeft() : Kind()
class EncryptionKeyPairRequest(): Kind()
val description: String = run { val description: String = run {
when(this) { when(this) {
@ -118,8 +130,8 @@ class ClosedGroupControlMessage() : ControlMessage() {
val kind = kind ?: return false val kind = kind ?: return false
return when(kind) { return when(kind) {
is Kind.New -> { is Kind.New -> {
!kind.publicKey.isEmpty && kind.name.isNotEmpty() && kind.encryptionKeyPair.publicKey != null !kind.publicKey.isEmpty && kind.name.isNotEmpty() && kind.encryptionKeyPair!!.publicKey != null
&& kind.encryptionKeyPair.privateKey != null && kind.members.isNotEmpty() && kind.admins.isNotEmpty() && kind.encryptionKeyPair!!.privateKey != null && kind.members.isNotEmpty() && kind.admins.isNotEmpty()
} }
is Kind.Update -> kind.name.isNotEmpty() is Kind.Update -> kind.name.isNotEmpty()
is Kind.EncryptionKeyPair -> true is Kind.EncryptionKeyPair -> true
@ -145,8 +157,8 @@ class ClosedGroupControlMessage() : ControlMessage() {
closedGroupControlMessage.publicKey = kind.publicKey closedGroupControlMessage.publicKey = kind.publicKey
closedGroupControlMessage.name = kind.name closedGroupControlMessage.name = kind.name
val encryptionKeyPair = SignalServiceProtos.KeyPair.newBuilder() val encryptionKeyPair = SignalServiceProtos.KeyPair.newBuilder()
encryptionKeyPair.publicKey = ByteString.copyFrom(kind.encryptionKeyPair.publicKey.serialize().removing05PrefixIfNeeded()) encryptionKeyPair.publicKey = ByteString.copyFrom(kind.encryptionKeyPair!!.publicKey.serialize().removing05PrefixIfNeeded())
encryptionKeyPair.privateKey = ByteString.copyFrom(kind.encryptionKeyPair.privateKey.serialize()) encryptionKeyPair.privateKey = ByteString.copyFrom(kind.encryptionKeyPair!!.privateKey.serialize())
closedGroupControlMessage.encryptionKeyPair = encryptionKeyPair.build() closedGroupControlMessage.encryptionKeyPair = encryptionKeyPair.build()
closedGroupControlMessage.addAllMembers(kind.members) closedGroupControlMessage.addAllMembers(kind.members)
closedGroupControlMessage.addAllAdmins(kind.admins) closedGroupControlMessage.addAllAdmins(kind.admins)

View File

@ -14,11 +14,13 @@ import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded
import org.session.libsignal.service.loki.utilities.toHexString import org.session.libsignal.service.loki.utilities.toHexString
import org.session.libsignal.utilities.Hex import org.session.libsignal.utilities.Hex
class ConfigurationMessage(val closedGroups: List<ClosedGroup>, val openGroups: List<String>, val contacts: List<Contact>, val displayName: String, val profilePicture: String?, val profileKey: ByteArray): ControlMessage() { class ConfigurationMessage(var closedGroups: List<ClosedGroup>, var openGroups: List<String>, var contacts: List<Contact>, var displayName: String, var profilePicture: String?, var profileKey: ByteArray): ControlMessage() {
class ClosedGroup(val publicKey: String, val name: String, val encryptionKeyPair: ECKeyPair, val members: List<String>, val admins: List<String>) { class ClosedGroup(var publicKey: String, var name: String, var encryptionKeyPair: ECKeyPair?, var members: List<String>, var admins: List<String>) {
val isValid: Boolean get() = members.isNotEmpty() && admins.isNotEmpty() val isValid: Boolean get() = members.isNotEmpty() && admins.isNotEmpty()
internal constructor(): this("", "", null, listOf(), listOf())
override fun toString(): String { override fun toString(): String {
return name return name
} }
@ -42,8 +44,8 @@ class ConfigurationMessage(val closedGroups: List<ClosedGroup>, val openGroups:
result.publicKey = ByteString.copyFrom(Hex.fromStringCondensed(publicKey)) result.publicKey = ByteString.copyFrom(Hex.fromStringCondensed(publicKey))
result.name = name result.name = name
val encryptionKeyPairAsProto = SignalServiceProtos.KeyPair.newBuilder() val encryptionKeyPairAsProto = SignalServiceProtos.KeyPair.newBuilder()
encryptionKeyPairAsProto.publicKey = ByteString.copyFrom(encryptionKeyPair.publicKey.serialize().removing05PrefixIfNeeded()) encryptionKeyPairAsProto.publicKey = ByteString.copyFrom(encryptionKeyPair!!.publicKey.serialize().removing05PrefixIfNeeded())
encryptionKeyPairAsProto.privateKey = ByteString.copyFrom(encryptionKeyPair.privateKey.serialize()) encryptionKeyPairAsProto.privateKey = ByteString.copyFrom(encryptionKeyPair!!.privateKey.serialize())
result.encryptionKeyPair = encryptionKeyPairAsProto.build() result.encryptionKeyPair = encryptionKeyPairAsProto.build()
result.addAllMembers(members.map { ByteString.copyFrom(Hex.fromStringCondensed(it)) }) result.addAllMembers(members.map { ByteString.copyFrom(Hex.fromStringCondensed(it)) })
result.addAllAdmins(admins.map { ByteString.copyFrom(Hex.fromStringCondensed(it)) }) result.addAllAdmins(admins.map { ByteString.copyFrom(Hex.fromStringCondensed(it)) })
@ -51,7 +53,10 @@ class ConfigurationMessage(val closedGroups: List<ClosedGroup>, 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 { companion object {
fun fromProto(proto: SignalServiceProtos.ConfigurationMessage.Contact): Contact? { fun fromProto(proto: SignalServiceProtos.ConfigurationMessage.Contact): Contact? {
if (!proto.hasName() || !proto.hasProfileKey()) return null if (!proto.hasName() || !proto.hasProfileKey()) return null
@ -128,6 +133,8 @@ class ConfigurationMessage(val closedGroups: List<ClosedGroup>, val openGroups:
} }
} }
internal constructor(): this(listOf(), listOf(), listOf(), "", null, byteArrayOf())
override fun toProto(): SignalServiceProtos.Content? { override fun toProto(): SignalServiceProtos.Content? {
val configurationProto = SignalServiceProtos.ConfigurationMessage.newBuilder() val configurationProto = SignalServiceProtos.ConfigurationMessage.newBuilder()
configurationProto.addAllClosedGroups(closedGroups.mapNotNull { it.toProto() }) configurationProto.addAllClosedGroups(closedGroups.mapNotNull { it.toProto() })

View File

@ -110,7 +110,7 @@ private fun MessageReceiver.handleConfigurationMessage(message: ConfigurationMes
val allClosedGroupPublicKeys = storage.getAllClosedGroupPublicKeys() val allClosedGroupPublicKeys = storage.getAllClosedGroupPublicKeys()
for (closeGroup in message.closedGroups) { for (closeGroup in message.closedGroups) {
if (allClosedGroupPublicKeys.contains(closeGroup.publicKey)) continue 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 } val allOpenGroups = storage.getAllOpenGroups().map { it.value.server }
for (openGroup in message.openGroups) { for (openGroup in message.openGroups) {
@ -222,7 +222,7 @@ private fun MessageReceiver.handleNewClosedGroup(message: ClosedGroupControlMess
val groupPublicKey = kind.publicKey.toByteArray().toHexString() val groupPublicKey = kind.publicKey.toByteArray().toHexString()
val members = kind.members.map { it.toByteArray().toHexString() } val members = kind.members.map { it.toByteArray().toHexString() }
val admins = kind.admins.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 // Parameter @sender:String is just for inserting incoming info message

View File

@ -76,12 +76,6 @@ object MessageSender {
// Set the timestamp, sender and recipient // Set the timestamp, sender and recipient
message.sentTimestamp ?: run { message.sentTimestamp = System.currentTimeMillis() } /* Visible messages will already have their sent timestamp set */ message.sentTimestamp ?: run { message.sentTimestamp = System.currentTimeMillis() } /* Visible messages will already have their sent timestamp set */
message.sender = userPublicKey message.sender = userPublicKey
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) val isSelfSend = (message.recipient == userPublicKey)
// Set the failure handler (need it here already for precondition failure handling) // Set the failure handler (need it here already for precondition failure handling)
fun handleFailure(error: Exception) { fun handleFailure(error: Exception) {
@ -91,6 +85,12 @@ object MessageSender {
} }
deferred.reject(error) 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
}
// Validate the message // Validate the message
if (!message.isValid()) { throw Error.InvalidMessage } if (!message.isValid()) { throw Error.InvalidMessage }
// Stop here if this is a self-send, unless it's: // Stop here if this is a self-send, unless it's:
@ -183,15 +183,14 @@ object MessageSender {
errorCount += 1 errorCount += 1
if (errorCount != promiseCount) { return@fail } // Only error out if all promises failed if (errorCount != promiseCount) { return@fail } // Only error out if all promises failed
handleFailure(it) handleFailure(it)
deferred.reject(it)
} }
} }
}.fail { }.fail {
Log.d("Loki", "Couldn't send message due to error: $it.") Log.d("Loki", "Couldn't send message due to error: $it.")
deferred.reject(it) handleFailure(it)
} }
} catch (exception: Exception) { } catch (exception: Exception) {
deferred.reject(exception) handleFailure(exception)
} }
return promise return promise
} }