|
|
@ -35,7 +35,7 @@ import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel as S
|
|
|
|
object MessageSender {
|
|
|
|
object MessageSender {
|
|
|
|
|
|
|
|
|
|
|
|
// Error
|
|
|
|
// Error
|
|
|
|
sealed class Error(val description: String) : Exception() {
|
|
|
|
sealed class Error(val description: String) : Exception(description) {
|
|
|
|
object InvalidMessage : Error("Invalid message.")
|
|
|
|
object InvalidMessage : Error("Invalid message.")
|
|
|
|
object ProtoConversionFailed : Error("Couldn't convert message to proto.")
|
|
|
|
object ProtoConversionFailed : Error("Couldn't convert message to proto.")
|
|
|
|
object ProofOfWorkCalculationFailed : Error("Proof of work calculation failed.")
|
|
|
|
object ProofOfWorkCalculationFailed : Error("Proof of work calculation failed.")
|
|
|
@ -50,6 +50,9 @@ object MessageSender {
|
|
|
|
object NoPrivateKey : Error("Couldn't find a private key associated with the given group public key.")
|
|
|
|
object NoPrivateKey : Error("Couldn't find a private key associated with the given group public key.")
|
|
|
|
object InvalidClosedGroupUpdate : Error("Invalid group update.")
|
|
|
|
object InvalidClosedGroupUpdate : Error("Invalid group update.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Precondition
|
|
|
|
|
|
|
|
class PreconditionFailure(val reason: String): Error(reason)
|
|
|
|
|
|
|
|
|
|
|
|
internal val isRetryable: Boolean = when (this) {
|
|
|
|
internal val isRetryable: Boolean = when (this) {
|
|
|
|
is InvalidMessage -> false
|
|
|
|
is InvalidMessage -> false
|
|
|
|
is ProtoConversionFailed -> false
|
|
|
|
is ProtoConversionFailed -> false
|
|
|
@ -73,7 +76,6 @@ object MessageSender {
|
|
|
|
val promise = deferred.promise
|
|
|
|
val promise = deferred.promise
|
|
|
|
val storage = MessagingConfiguration.shared.storage
|
|
|
|
val storage = MessagingConfiguration.shared.storage
|
|
|
|
val userPublicKey = storage.getUserPublicKey()
|
|
|
|
val userPublicKey = storage.getUserPublicKey()
|
|
|
|
val preconditionFailure = Exception("Destination should not be open groups!")
|
|
|
|
|
|
|
|
// 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
|
|
|
@ -90,7 +92,7 @@ object MessageSender {
|
|
|
|
when (destination) {
|
|
|
|
when (destination) {
|
|
|
|
is Destination.Contact -> message.recipient = destination.publicKey
|
|
|
|
is Destination.Contact -> message.recipient = destination.publicKey
|
|
|
|
is Destination.ClosedGroup -> message.recipient = destination.groupPublicKey
|
|
|
|
is Destination.ClosedGroup -> message.recipient = destination.groupPublicKey
|
|
|
|
is Destination.OpenGroup -> throw preconditionFailure
|
|
|
|
is Destination.OpenGroup -> throw Error.PreconditionFailure("Destination should not be open groups!")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Validate the message
|
|
|
|
// Validate the message
|
|
|
|
if (!message.isValid()) { throw Error.InvalidMessage }
|
|
|
|
if (!message.isValid()) { throw Error.InvalidMessage }
|
|
|
@ -128,7 +130,7 @@ object MessageSender {
|
|
|
|
val encryptionKeyPair = MessagingConfiguration.shared.storage.getLatestClosedGroupEncryptionKeyPair(destination.groupPublicKey)!!
|
|
|
|
val encryptionKeyPair = MessagingConfiguration.shared.storage.getLatestClosedGroupEncryptionKeyPair(destination.groupPublicKey)!!
|
|
|
|
ciphertext = MessageSenderEncryption.encryptWithSessionProtocol(plaintext, encryptionKeyPair.hexEncodedPublicKey)
|
|
|
|
ciphertext = MessageSenderEncryption.encryptWithSessionProtocol(plaintext, encryptionKeyPair.hexEncodedPublicKey)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
is Destination.OpenGroup -> throw preconditionFailure
|
|
|
|
is Destination.OpenGroup -> throw Error.PreconditionFailure("Destination should not be open groups!")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Wrap the result
|
|
|
|
// Wrap the result
|
|
|
|
val kind: SignalServiceProtos.Envelope.Type
|
|
|
|
val kind: SignalServiceProtos.Envelope.Type
|
|
|
@ -142,7 +144,7 @@ object MessageSender {
|
|
|
|
kind = SignalServiceProtos.Envelope.Type.CLOSED_GROUP_CIPHERTEXT
|
|
|
|
kind = SignalServiceProtos.Envelope.Type.CLOSED_GROUP_CIPHERTEXT
|
|
|
|
senderPublicKey = destination.groupPublicKey
|
|
|
|
senderPublicKey = destination.groupPublicKey
|
|
|
|
}
|
|
|
|
}
|
|
|
|
is Destination.OpenGroup -> throw preconditionFailure
|
|
|
|
is Destination.OpenGroup -> throw Error.PreconditionFailure("Destination should not be open groups!")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
val wrappedMessage = MessageWrapper.wrap(kind, message.sentTimestamp!!, senderPublicKey, ciphertext)
|
|
|
|
val wrappedMessage = MessageWrapper.wrap(kind, message.sentTimestamp!!, senderPublicKey, ciphertext)
|
|
|
|
// Calculate proof of work
|
|
|
|
// Calculate proof of work
|
|
|
@ -199,34 +201,31 @@ object MessageSender {
|
|
|
|
private fun sendToOpenGroupDestination(destination: Destination, message: Message): Promise<Unit, Exception> {
|
|
|
|
private fun sendToOpenGroupDestination(destination: Destination, message: Message): Promise<Unit, Exception> {
|
|
|
|
val deferred = deferred<Unit, Exception>()
|
|
|
|
val deferred = deferred<Unit, Exception>()
|
|
|
|
val storage = MessagingConfiguration.shared.storage
|
|
|
|
val storage = MessagingConfiguration.shared.storage
|
|
|
|
val preconditionFailure = Exception("Destination should not be contacts or closed groups!")
|
|
|
|
|
|
|
|
message.sentTimestamp ?: run { message.sentTimestamp = System.currentTimeMillis() }
|
|
|
|
message.sentTimestamp ?: run { message.sentTimestamp = System.currentTimeMillis() }
|
|
|
|
message.sender = storage.getUserPublicKey()
|
|
|
|
message.sender = storage.getUserPublicKey()
|
|
|
|
|
|
|
|
// Set the failure handler (need it here already for precondition failure handling)
|
|
|
|
|
|
|
|
fun handleFailure(error: Exception) {
|
|
|
|
|
|
|
|
handleFailedMessageSend(message, error)
|
|
|
|
|
|
|
|
deferred.reject(error)
|
|
|
|
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
val server: String
|
|
|
|
val server: String
|
|
|
|
val channel: Long
|
|
|
|
val channel: Long
|
|
|
|
when (destination) {
|
|
|
|
when (destination) {
|
|
|
|
is Destination.Contact -> throw preconditionFailure
|
|
|
|
is Destination.Contact -> throw Error.PreconditionFailure("Destination should not be contacts!")
|
|
|
|
is Destination.ClosedGroup -> throw preconditionFailure
|
|
|
|
is Destination.ClosedGroup -> throw Error.PreconditionFailure("Destination should not be closed groups!")
|
|
|
|
is Destination.OpenGroup -> {
|
|
|
|
is Destination.OpenGroup -> {
|
|
|
|
message.recipient = "${destination.server}.${destination.channel}"
|
|
|
|
message.recipient = "${destination.server}.${destination.channel}"
|
|
|
|
server = destination.server
|
|
|
|
server = destination.server
|
|
|
|
channel = destination.channel
|
|
|
|
channel = destination.channel
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Set the failure handler (need it here already for precondition failure handling)
|
|
|
|
|
|
|
|
fun handleFailure(error: Exception) {
|
|
|
|
|
|
|
|
handleFailedMessageSend(message, error)
|
|
|
|
|
|
|
|
deferred.reject(error)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Validate the message
|
|
|
|
// Validate the message
|
|
|
|
if (message !is VisibleMessage || !message.isValid()) {
|
|
|
|
if (message !is VisibleMessage || !message.isValid()) {
|
|
|
|
handleFailure(Error.InvalidMessage)
|
|
|
|
|
|
|
|
throw Error.InvalidMessage
|
|
|
|
throw Error.InvalidMessage
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Convert the message to an open group message
|
|
|
|
// Convert the message to an open group message
|
|
|
|
val openGroupMessage = OpenGroupMessage.from(message, server) ?: kotlin.run {
|
|
|
|
val openGroupMessage = OpenGroupMessage.from(message, server) ?: kotlin.run {
|
|
|
|
handleFailure(Error.InvalidMessage)
|
|
|
|
|
|
|
|
throw Error.InvalidMessage
|
|
|
|
throw Error.InvalidMessage
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Send the result
|
|
|
|
// Send the result
|
|
|
@ -238,7 +237,7 @@ object MessageSender {
|
|
|
|
handleFailure(it)
|
|
|
|
handleFailure(it)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (exception: Exception) {
|
|
|
|
} catch (exception: Exception) {
|
|
|
|
deferred.reject(exception)
|
|
|
|
handleFailure(exception)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return deferred.promise
|
|
|
|
return deferred.promise
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -246,7 +245,8 @@ object MessageSender {
|
|
|
|
// Result Handling
|
|
|
|
// Result Handling
|
|
|
|
fun handleSuccessfulMessageSend(message: Message, destination: Destination, isSyncMessage: Boolean = false) {
|
|
|
|
fun handleSuccessfulMessageSend(message: Message, destination: Destination, isSyncMessage: Boolean = false) {
|
|
|
|
val storage = MessagingConfiguration.shared.storage
|
|
|
|
val storage = MessagingConfiguration.shared.storage
|
|
|
|
val messageId = storage.getMessageIdInDatabase(message.sentTimestamp!!, message.sender!!) ?: return
|
|
|
|
val userPublicKey = storage.getUserPublicKey()!!
|
|
|
|
|
|
|
|
val messageId = storage.getMessageIdInDatabase(message.sentTimestamp!!, message.sender?:userPublicKey) ?: return
|
|
|
|
// Ignore future self-sends
|
|
|
|
// Ignore future self-sends
|
|
|
|
storage.addReceivedMessageTimestamp(message.sentTimestamp!!)
|
|
|
|
storage.addReceivedMessageTimestamp(message.sentTimestamp!!)
|
|
|
|
// Track the open group server message ID
|
|
|
|
// Track the open group server message ID
|
|
|
@ -254,17 +254,16 @@ object MessageSender {
|
|
|
|
storage.setOpenGroupServerMessageID(messageId, message.openGroupServerMessageID!!)
|
|
|
|
storage.setOpenGroupServerMessageID(messageId, message.openGroupServerMessageID!!)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Mark the message as sent
|
|
|
|
// Mark the message as sent
|
|
|
|
storage.markAsSent(message.sentTimestamp!!, message.sender!!)
|
|
|
|
storage.markAsSent(message.sentTimestamp!!, message.sender?:userPublicKey)
|
|
|
|
storage.markUnidentified(message.sentTimestamp!!, message.sender!!)
|
|
|
|
storage.markUnidentified(message.sentTimestamp!!, message.sender?:userPublicKey)
|
|
|
|
// Start the disappearing messages timer if needed
|
|
|
|
// Start the disappearing messages timer if needed
|
|
|
|
if (message is VisibleMessage && !isSyncMessage) {
|
|
|
|
if (message is VisibleMessage && !isSyncMessage) {
|
|
|
|
SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(message.sentTimestamp!!, message.sender!!)
|
|
|
|
SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(message.sentTimestamp!!, message.sender?:userPublicKey)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Sync the message if:
|
|
|
|
// Sync the message if:
|
|
|
|
// • it's a visible message
|
|
|
|
// • it's a visible message
|
|
|
|
// • the destination was a contact
|
|
|
|
// • the destination was a contact
|
|
|
|
// • we didn't sync it already
|
|
|
|
// • we didn't sync it already
|
|
|
|
val userPublicKey = storage.getUserPublicKey()!!
|
|
|
|
|
|
|
|
if (destination is Destination.Contact && !isSyncMessage) {
|
|
|
|
if (destination is Destination.Contact && !isSyncMessage) {
|
|
|
|
if (message is VisibleMessage) { message.syncTarget = destination.publicKey }
|
|
|
|
if (message is VisibleMessage) { message.syncTarget = destination.publicKey }
|
|
|
|
if (message is ExpirationTimerUpdate) { message.syncTarget = destination.publicKey }
|
|
|
|
if (message is ExpirationTimerUpdate) { message.syncTarget = destination.publicKey }
|
|
|
@ -274,7 +273,8 @@ object MessageSender {
|
|
|
|
|
|
|
|
|
|
|
|
fun handleFailedMessageSend(message: Message, error: Exception) {
|
|
|
|
fun handleFailedMessageSend(message: Message, error: Exception) {
|
|
|
|
val storage = MessagingConfiguration.shared.storage
|
|
|
|
val storage = MessagingConfiguration.shared.storage
|
|
|
|
storage.setErrorMessage(message.sentTimestamp!!, message.sender!!, error)
|
|
|
|
val userPublicKey = storage.getUserPublicKey()!!
|
|
|
|
|
|
|
|
storage.setErrorMessage(message.sentTimestamp!!, message.sender?:userPublicKey, error)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Convenience
|
|
|
|
// Convenience
|
|
|
|