mirror of
https://github.com/oxen-io/session-android.git
synced 2025-08-24 12:29:25 +00:00
feat: hacky workaround for new protobuf encryption branches !
This commit is contained in:
@@ -100,7 +100,8 @@ class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long)
|
||||
handleFailure(Error.NoSender, null)
|
||||
return
|
||||
}
|
||||
if (!threadRecipient.isGroupRecipient && contact?.isTrusted != true && storage.getUserPublicKey() != sender) {
|
||||
|
||||
if (!storage.shouldAutoDownloadAttachments(threadRecipient)) {
|
||||
// if we aren't receiving a group message, a message from ourselves (self-send) and the contact sending is not trusted:
|
||||
// do not continue, but do not fail
|
||||
handleFailure(Error.NoSender, null)
|
||||
|
@@ -8,6 +8,7 @@ import kotlinx.coroutines.runBlocking
|
||||
import nl.komponents.kovenant.Promise
|
||||
import nl.komponents.kovenant.task
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.messaging.messages.Destination
|
||||
import org.session.libsession.messaging.messages.Message
|
||||
import org.session.libsession.messaging.messages.control.CallMessage
|
||||
import org.session.libsession.messaging.messages.control.ClosedGroupControlMessage
|
||||
@@ -28,18 +29,19 @@ import org.session.libsession.messaging.sending_receiving.handleOpenGroupReactio
|
||||
import org.session.libsession.messaging.sending_receiving.handleUnsendRequest
|
||||
import org.session.libsession.messaging.sending_receiving.handleVisibleMessage
|
||||
import org.session.libsession.messaging.utilities.Data
|
||||
import org.session.libsignal.utilities.SessionId
|
||||
import org.session.libsession.messaging.utilities.SodiumUtilities
|
||||
import org.session.libsession.utilities.SSKEnvironment
|
||||
import org.session.libsignal.protos.UtilProtos
|
||||
import org.session.libsignal.utilities.IdPrefix
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.session.libsignal.utilities.SessionId
|
||||
|
||||
data class MessageReceiveParameters(
|
||||
val data: ByteArray,
|
||||
val serverHash: String? = null,
|
||||
val openGroupMessageServerID: Long? = null,
|
||||
val reactions: Map<String, OpenGroupApi.Reaction>? = null
|
||||
val reactions: Map<String, OpenGroupApi.Reaction>? = null,
|
||||
val closedGroup: Destination.ClosedGroup? = null
|
||||
)
|
||||
|
||||
class BatchMessageReceiveJob(
|
||||
@@ -69,6 +71,7 @@ class BatchMessageReceiveJob(
|
||||
private val SERVER_HASH_KEY = "serverHash"
|
||||
private val OPEN_GROUP_MESSAGE_SERVER_ID_KEY = "openGroupMessageServerID"
|
||||
private val OPEN_GROUP_ID_KEY = "open_group_id"
|
||||
private val CLOSED_GROUP_DESTINATION_KEY = "closed_group_destination"
|
||||
}
|
||||
|
||||
private fun shouldCreateThread(parsedMessage: ParsedMessage): Boolean {
|
||||
@@ -108,7 +111,13 @@ class BatchMessageReceiveJob(
|
||||
messages.forEach { messageParameters ->
|
||||
val (data, serverHash, openGroupMessageServerID) = messageParameters
|
||||
try {
|
||||
val (message, proto) = MessageReceiver.parse(data, openGroupMessageServerID, openGroupPublicKey = serverPublicKey, currentClosedGroups = currentClosedGroups)
|
||||
val (message, proto) = MessageReceiver.parse(
|
||||
data,
|
||||
openGroupMessageServerID,
|
||||
openGroupPublicKey = serverPublicKey,
|
||||
currentClosedGroups = currentClosedGroups,
|
||||
closedGroupSessionId = messageParameters.closedGroup?.publicKey
|
||||
)
|
||||
message.serverHash = serverHash
|
||||
val parsedParams = ParsedMessage(messageParameters, message, proto)
|
||||
val threadID = Message.getThreadId(message, openGroupID, storage, shouldCreateThread(parsedParams)) ?: NO_THREAD_MAPPING
|
||||
@@ -262,12 +271,14 @@ class BatchMessageReceiveJob(
|
||||
.build()
|
||||
val serverHashes = messages.map { it.serverHash.orEmpty() }
|
||||
val openGroupServerIds = messages.map { it.openGroupMessageServerID ?: -1L }
|
||||
val closedGroups = messages.map { it.closedGroup?.publicKey.orEmpty() }
|
||||
return Data.Builder()
|
||||
.putInt(NUM_MESSAGES_KEY, arraySize)
|
||||
.putByteArray(DATA_KEY, dataArrays.toByteArray())
|
||||
.putString(OPEN_GROUP_ID_KEY, openGroupID)
|
||||
.putLongArray(OPEN_GROUP_MESSAGE_SERVER_ID_KEY, openGroupServerIds.toLongArray())
|
||||
.putStringArray(SERVER_HASH_KEY, serverHashes.toTypedArray())
|
||||
.putStringArray(CLOSED_GROUP_DESTINATION_KEY, closedGroups.toTypedArray())
|
||||
.build()
|
||||
}
|
||||
|
||||
@@ -283,11 +294,22 @@ class BatchMessageReceiveJob(
|
||||
if (data.hasStringArray(SERVER_HASH_KEY)) data.getStringArray(SERVER_HASH_KEY) else arrayOf()
|
||||
val openGroupMessageServerIDs = data.getLongArray(OPEN_GROUP_MESSAGE_SERVER_ID_KEY)
|
||||
val openGroupID = data.getStringOrDefault(OPEN_GROUP_ID_KEY, null)
|
||||
val closedGroups =
|
||||
if (data.hasStringArray(CLOSED_GROUP_DESTINATION_KEY)) data.getStringArray(CLOSED_GROUP_DESTINATION_KEY)
|
||||
else arrayOf()
|
||||
|
||||
val parameters = (0 until numMessages).map { index ->
|
||||
val serverHash = serverHashes[index].let { if (it.isEmpty()) null else it }
|
||||
val serverId = openGroupMessageServerIDs[index].let { if (it == -1L) null else it }
|
||||
MessageReceiveParameters(contents[index], serverHash, serverId)
|
||||
val closedGroup = closedGroups.getOrNull(index)?.let {
|
||||
if (it.isEmpty()) null else Destination.ClosedGroup(it)
|
||||
}
|
||||
MessageReceiveParameters(
|
||||
data = contents[index],
|
||||
serverHash = serverHash,
|
||||
openGroupMessageServerID = serverId,
|
||||
closedGroup = closedGroup
|
||||
)
|
||||
}
|
||||
|
||||
return BatchMessageReceiveJob(parameters, openGroupID)
|
||||
|
@@ -17,6 +17,7 @@ import org.session.libsession.messaging.utilities.SodiumUtilities
|
||||
import org.session.libsession.snode.SnodeAPI
|
||||
import org.session.libsignal.crypto.PushTransportDetails
|
||||
import org.session.libsignal.protos.SignalServiceProtos
|
||||
import org.session.libsignal.protos.SignalServiceProtos.Envelope
|
||||
import org.session.libsignal.utilities.IdPrefix
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.session.libsignal.utilities.SessionId
|
||||
@@ -53,22 +54,24 @@ object MessageReceiver {
|
||||
isOutgoing: Boolean? = null,
|
||||
otherBlindedPublicKey: String? = null,
|
||||
openGroupPublicKey: String? = null,
|
||||
currentClosedGroups: Set<String>?
|
||||
currentClosedGroups: Set<String>?,
|
||||
closedGroupSessionId: String? = null,
|
||||
): Pair<Message, SignalServiceProtos.Content> {
|
||||
val storage = MessagingModuleConfiguration.shared.storage
|
||||
val userPublicKey = storage.getUserPublicKey()
|
||||
val isOpenGroupMessage = (openGroupServerID != null)
|
||||
// Parse the envelope
|
||||
val envelope = SignalServiceProtos.Envelope.parseFrom(data)
|
||||
// Decrypt the contents
|
||||
val ciphertext = envelope.content ?: run {
|
||||
throw Error.NoData
|
||||
}
|
||||
var plaintext: ByteArray? = null
|
||||
var sender: String? = null
|
||||
var groupPublicKey: String? = null
|
||||
// Parse the envelope
|
||||
val envelope = Envelope.parseFrom(data) ?: throw Error.InvalidMessage
|
||||
// Decrypt the contents
|
||||
val envelopeContent = envelope.content ?: run {
|
||||
throw Error.NoData
|
||||
}
|
||||
|
||||
if (isOpenGroupMessage) {
|
||||
plaintext = envelope.content.toByteArray()
|
||||
plaintext = envelopeContent.toByteArray()
|
||||
sender = envelope.source
|
||||
} else {
|
||||
when (envelope.type) {
|
||||
@@ -77,7 +80,7 @@ object MessageReceiver {
|
||||
openGroupPublicKey ?: throw Error.InvalidGroupPublicKey
|
||||
otherBlindedPublicKey ?: throw Error.DecryptionFailed
|
||||
val decryptionResult = MessageDecrypter.decryptBlinded(
|
||||
ciphertext.toByteArray(),
|
||||
envelopeContent.toByteArray(),
|
||||
isOutgoing ?: false,
|
||||
otherBlindedPublicKey,
|
||||
openGroupPublicKey
|
||||
@@ -86,26 +89,18 @@ object MessageReceiver {
|
||||
sender = decryptionResult.second
|
||||
} else {
|
||||
val userX25519KeyPair = MessagingModuleConfiguration.shared.storage.getUserX25519KeyPair()
|
||||
val decryptionResult = MessageDecrypter.decrypt(ciphertext.toByteArray(), userX25519KeyPair)
|
||||
val decryptionResult = MessageDecrypter.decrypt(envelopeContent.toByteArray(), userX25519KeyPair)
|
||||
plaintext = decryptionResult.first
|
||||
sender = decryptionResult.second
|
||||
}
|
||||
}
|
||||
SignalServiceProtos.Envelope.Type.CLOSED_GROUP_MESSAGE -> {
|
||||
val hexEncodedGroupPublicKey = envelope.source
|
||||
val hexEncodedGroupPublicKey = closedGroupSessionId ?: envelope.source
|
||||
val sessionId = SessionId.from(hexEncodedGroupPublicKey)
|
||||
if (sessionId.prefix == IdPrefix.GROUP) {
|
||||
val configFactory = MessagingModuleConfiguration.shared.configFactory
|
||||
configFactory.getGroupKeysConfig(sessionId)?.use { config ->
|
||||
config.decrypt(ciphertext.toByteArray())?.let { (decrypted, senderSessionId) ->
|
||||
plaintext = decrypted
|
||||
sender = senderSessionId.hexString()
|
||||
groupPublicKey = envelope.source
|
||||
}
|
||||
}
|
||||
if (plaintext == null) {
|
||||
throw Error.DecryptionFailed
|
||||
}
|
||||
plaintext = envelopeContent.toByteArray()
|
||||
sender = envelope.source
|
||||
groupPublicKey = hexEncodedGroupPublicKey
|
||||
} else {
|
||||
if (!MessagingModuleConfiguration.shared.storage.isLegacyClosedGroup(hexEncodedGroupPublicKey)) {
|
||||
throw Error.InvalidGroupPublicKey
|
||||
@@ -119,7 +114,7 @@ object MessageReceiver {
|
||||
var encryptionKeyPair = encryptionKeyPairs.removeLast()
|
||||
fun decrypt() {
|
||||
try {
|
||||
val decryptionResult = MessageDecrypter.decrypt(ciphertext.toByteArray(), encryptionKeyPair)
|
||||
val decryptionResult = MessageDecrypter.decrypt(envelopeContent.toByteArray(), encryptionKeyPair)
|
||||
plaintext = decryptionResult.first
|
||||
sender = decryptionResult.second
|
||||
} catch (e: Exception) {
|
||||
@@ -132,7 +127,7 @@ object MessageReceiver {
|
||||
}
|
||||
}
|
||||
}
|
||||
groupPublicKey = envelope.source
|
||||
groupPublicKey = hexEncodedGroupPublicKey
|
||||
decrypt()
|
||||
}
|
||||
}
|
||||
|
@@ -125,25 +125,8 @@ object MessageSender {
|
||||
val proto = message.toProto() ?: throw Error.ProtoConversionFailed
|
||||
// Serialize the protobuf
|
||||
val plaintext = PushTransportDetails.getPaddedMessageBody(proto.toByteArray())
|
||||
// Encrypt the serialized protobuf
|
||||
val ciphertext = when (destination) {
|
||||
is Destination.Contact -> MessageEncrypter.encrypt(plaintext, destination.publicKey)
|
||||
is Destination.LegacyClosedGroup -> {
|
||||
val encryptionKeyPair =
|
||||
MessagingModuleConfiguration.shared.storage.getLatestClosedGroupEncryptionKeyPair(
|
||||
destination.groupPublicKey
|
||||
)!!
|
||||
MessageEncrypter.encrypt(plaintext, encryptionKeyPair.hexEncodedPublicKey)
|
||||
}
|
||||
is Destination.ClosedGroup -> {
|
||||
val groupKeys = configFactory.getGroupKeysConfig(SessionId.from(destination.publicKey)) ?: throw Error.NoKeyPair
|
||||
groupKeys.use { keys ->
|
||||
keys.encrypt(proto.toByteArray())
|
||||
}
|
||||
}
|
||||
else -> throw IllegalStateException("Destination should not be open group.")
|
||||
}
|
||||
// Wrap the result
|
||||
|
||||
// Envelope information
|
||||
val kind: SignalServiceProtos.Envelope.Type
|
||||
val senderPublicKey: String
|
||||
when (destination) {
|
||||
@@ -161,7 +144,34 @@ object MessageSender {
|
||||
}
|
||||
else -> throw IllegalStateException("Destination should not be open group.")
|
||||
}
|
||||
val wrappedMessage = MessageWrapper.wrap(kind, message.sentTimestamp!!, senderPublicKey, ciphertext)
|
||||
|
||||
// Encrypt the serialized protobuf
|
||||
val ciphertext = when (destination) {
|
||||
is Destination.Contact -> MessageEncrypter.encrypt(plaintext, destination.publicKey)
|
||||
is Destination.LegacyClosedGroup -> {
|
||||
val encryptionKeyPair =
|
||||
MessagingModuleConfiguration.shared.storage.getLatestClosedGroupEncryptionKeyPair(
|
||||
destination.groupPublicKey
|
||||
)!!
|
||||
MessageEncrypter.encrypt(plaintext, encryptionKeyPair.hexEncodedPublicKey)
|
||||
}
|
||||
is Destination.ClosedGroup -> {
|
||||
val groupKeys = configFactory.getGroupKeysConfig(SessionId.from(destination.publicKey)) ?: throw Error.NoKeyPair
|
||||
val envelope = MessageWrapper.createEnvelope(kind, message.sentTimestamp!!, senderPublicKey, proto.toByteArray())
|
||||
groupKeys.use { keys ->
|
||||
keys.encrypt(envelope.toByteArray())
|
||||
}
|
||||
}
|
||||
else -> throw IllegalStateException("Destination should not be open group.")
|
||||
}
|
||||
// Wrap the result using envelope information
|
||||
val wrappedMessage = when (destination) {
|
||||
is Destination.ClosedGroup -> {
|
||||
// encrypted bytes from the above closed group encryption and envelope steps
|
||||
ciphertext
|
||||
}
|
||||
else -> MessageWrapper.wrap(kind, message.sentTimestamp!!, senderPublicKey, ciphertext)
|
||||
}
|
||||
val base64EncodedData = Base64.encodeBytes(wrappedMessage)
|
||||
// Send the result
|
||||
return SnodeMessage(
|
||||
|
@@ -165,7 +165,7 @@ class ClosedGroupPoller(private val executor: CoroutineScope,
|
||||
keysIndex -> handleKeyPoll(response, keys, info, members)
|
||||
infoIndex -> handleInfo(response, info)
|
||||
membersIndex -> handleMembers(response, members)
|
||||
messageIndex -> handleMessages(response, snode)
|
||||
messageIndex -> handleMessages(response, snode, keys)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,11 +234,13 @@ class ClosedGroupPoller(private val executor: CoroutineScope,
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleMessages(response: RawResponse, snode: Snode) {
|
||||
private fun handleMessages(response: RawResponse, snode: Snode, keysConfig: GroupKeysConfig) {
|
||||
val body = response["body"] as RawResponse
|
||||
val messages = SnodeAPI.parseRawMessagesResponse(body, snode, closedGroupSessionId.hexString())
|
||||
val messages = SnodeAPI.parseRawMessagesResponse(body, snode, closedGroupSessionId.hexString()) {
|
||||
return@parseRawMessagesResponse keysConfig.decrypt(it)
|
||||
}
|
||||
val parameters = messages.map { (envelope, serverHash) ->
|
||||
MessageReceiveParameters(envelope.toByteArray(), serverHash = serverHash)
|
||||
MessageReceiveParameters(envelope.toByteArray(), serverHash = serverHash, closedGroup = Destination.ClosedGroup(closedGroupSessionId.hexString()))
|
||||
}
|
||||
parameters.chunked(BatchMessageReceiveJob.BATCH_DEFAULT_NUMBER).forEach { chunk ->
|
||||
val job = BatchMessageReceiveJob(chunk)
|
||||
|
@@ -1,10 +1,10 @@
|
||||
package org.session.libsession.messaging.utilities
|
||||
|
||||
import com.google.protobuf.ByteString
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.session.libsignal.protos.SignalServiceProtos.Envelope
|
||||
import org.session.libsignal.protos.WebSocketProtos.WebSocketMessage
|
||||
import org.session.libsignal.protos.WebSocketProtos.WebSocketRequestMessage
|
||||
import org.session.libsignal.utilities.Log
|
||||
import java.security.SecureRandom
|
||||
|
||||
object MessageWrapper {
|
||||
@@ -32,7 +32,7 @@ object MessageWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
private fun createEnvelope(type: Envelope.Type, timestamp: Long, senderPublicKey: String, content: ByteArray): Envelope {
|
||||
fun createEnvelope(type: Envelope.Type, timestamp: Long, senderPublicKey: String, content: ByteArray): Envelope {
|
||||
try {
|
||||
val builder = Envelope.newBuilder()
|
||||
builder.type = type
|
||||
|
@@ -29,6 +29,7 @@ import org.session.libsignal.utilities.Hex
|
||||
import org.session.libsignal.utilities.JsonUtil
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.session.libsignal.utilities.Namespace
|
||||
import org.session.libsignal.utilities.SessionId
|
||||
import org.session.libsignal.utilities.Snode
|
||||
import org.session.libsignal.utilities.ThreadUtils
|
||||
import org.session.libsignal.utilities.prettifiedDescription
|
||||
@@ -851,14 +852,21 @@ object SnodeAPI {
|
||||
}
|
||||
}
|
||||
|
||||
fun parseRawMessagesResponse(rawResponse: RawResponse, snode: Snode, publicKey: String, namespace: Int = 0, updateLatestHash: Boolean = true, updateStoredHashes: Boolean = true): List<Pair<SignalServiceProtos.Envelope, String?>> {
|
||||
fun parseRawMessagesResponse(rawResponse: RawResponse,
|
||||
snode: Snode,
|
||||
publicKey: String,
|
||||
namespace: Int = 0,
|
||||
updateLatestHash: Boolean = true,
|
||||
updateStoredHashes: Boolean = true,
|
||||
decrypt: ((ByteArray) -> Pair<ByteArray, SessionId>?)? = null
|
||||
): List<Pair<SignalServiceProtos.Envelope, String?>> {
|
||||
val messages = rawResponse["messages"] as? List<*>
|
||||
return if (messages != null) {
|
||||
if (updateLatestHash) {
|
||||
updateLastMessageHashValueIfPossible(snode, publicKey, messages, namespace)
|
||||
}
|
||||
val newRawMessages = removeDuplicates(publicKey, messages, namespace, updateStoredHashes)
|
||||
return parseEnvelopes(newRawMessages)
|
||||
return parseEnvelopes(newRawMessages, decrypt)
|
||||
} else {
|
||||
listOf()
|
||||
}
|
||||
@@ -895,14 +903,20 @@ object SnodeAPI {
|
||||
return result
|
||||
}
|
||||
|
||||
private fun parseEnvelopes(rawMessages: List<*>): List<Pair<SignalServiceProtos.Envelope, String?>> {
|
||||
private fun parseEnvelopes(rawMessages: List<*>, decrypt: ((ByteArray)->Pair<ByteArray, SessionId>?)?): List<Pair<SignalServiceProtos.Envelope, String?>> {
|
||||
return rawMessages.mapNotNull { rawMessage ->
|
||||
val rawMessageAsJSON = rawMessage as? Map<*, *>
|
||||
val base64EncodedData = rawMessageAsJSON?.get("data") as? String
|
||||
val data = base64EncodedData?.let { Base64.decode(it) }
|
||||
if (data != null) {
|
||||
try {
|
||||
Pair(MessageWrapper.unwrap(data), rawMessageAsJSON.get("hash") as? String)
|
||||
if (decrypt != null) {
|
||||
val (decrypted, sender) = decrypt(data)!!
|
||||
val envelope = SignalServiceProtos.Envelope.parseFrom(decrypted).toBuilder()
|
||||
envelope.source = sender.hexString()
|
||||
Pair(envelope.build(),rawMessageAsJSON.get("hash") as? String)
|
||||
}
|
||||
else Pair(MessageWrapper.unwrap(data), rawMessageAsJSON.get("hash") as? String)
|
||||
} catch (e: Exception) {
|
||||
Log.d("Loki", "Failed to unwrap data for message: ${rawMessage.prettifiedDescription()}.")
|
||||
null
|
||||
|
Reference in New Issue
Block a user