mirror of
https://github.com/oxen-io/session-android.git
synced 2023-12-14 02:53:01 +01:00
feat: hacky workaround for new protobuf encryption branches !
This commit is contained in:
parent
fcb1c56edb
commit
00ad9cf39f
|
@ -82,7 +82,7 @@ Java_network_loki_messenger_libsession_1util_ConfigBase_confirmPushed(JNIEnv *en
|
||||||
|
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#pragma ide diagnostic ignored "bugprone-reserved-identifier"
|
#pragma ide diagnostic ignored "bugprone-reserved-identifier"
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jobject JNICALL
|
||||||
Java_network_loki_messenger_libsession_1util_ConfigBase_merge___3Lkotlin_Pair_2(JNIEnv *env, jobject thiz,
|
Java_network_loki_messenger_libsession_1util_ConfigBase_merge___3Lkotlin_Pair_2(JNIEnv *env, jobject thiz,
|
||||||
jobjectArray to_merge) {
|
jobjectArray to_merge) {
|
||||||
std::lock_guard lock{util::util_mutex_};
|
std::lock_guard lock{util::util_mutex_};
|
||||||
|
@ -94,21 +94,31 @@ Java_network_loki_messenger_libsession_1util_ConfigBase_merge___3Lkotlin_Pair_2(
|
||||||
auto pair = extractHashAndData(env, jElement);
|
auto pair = extractHashAndData(env, jElement);
|
||||||
configs.push_back(pair);
|
configs.push_back(pair);
|
||||||
}
|
}
|
||||||
return conf->merge(configs);
|
auto returned = conf->merge(configs);
|
||||||
|
auto string_stack = util::build_string_stack(env, returned);
|
||||||
|
return string_stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jobject JNICALL
|
||||||
Java_network_loki_messenger_libsession_1util_ConfigBase_merge__Lkotlin_Pair_2(JNIEnv *env, jobject thiz,
|
Java_network_loki_messenger_libsession_1util_ConfigBase_merge__Lkotlin_Pair_2(JNIEnv *env, jobject thiz,
|
||||||
jobject to_merge) {
|
jobject to_merge) {
|
||||||
std::lock_guard lock{util::util_mutex_};
|
std::lock_guard lock{util::util_mutex_};
|
||||||
auto conf = ptrToConfigBase(env, thiz);
|
auto conf = ptrToConfigBase(env, thiz);
|
||||||
std::vector<std::pair<std::string, session::ustring>> configs = {extractHashAndData(env, to_merge)};
|
std::vector<std::pair<std::string, session::ustring>> configs = {extractHashAndData(env, to_merge)};
|
||||||
return conf->merge(configs);
|
auto returned = conf->merge(configs);
|
||||||
|
auto string_stack = util::build_string_stack(env, returned);
|
||||||
|
return string_stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
}
|
}
|
||||||
extern "C"
|
extern "C"
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_network_loki_messenger_libsession_1util_ConfigBase_configNamespace(JNIEnv *env, jobject thiz) {
|
||||||
|
auto conf = ptrToConfigBase(env, thiz);
|
||||||
|
return (std::int16_t) conf->storage_namespace();
|
||||||
|
}
|
||||||
|
extern "C"
|
||||||
JNIEXPORT jclass JNICALL
|
JNIEXPORT jclass JNICALL
|
||||||
Java_network_loki_messenger_libsession_1util_ConfigBase_00024Companion_kindFor(JNIEnv *env,
|
Java_network_loki_messenger_libsession_1util_ConfigBase_00024Companion_kindFor(JNIEnv *env,
|
||||||
jobject thiz,
|
jobject thiz,
|
||||||
|
|
|
@ -186,6 +186,17 @@ namespace util {
|
||||||
return group_member;
|
return group_member;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jobject build_string_stack(JNIEnv* env, std::vector<std::string> to_add) {
|
||||||
|
jclass stack_class = env->FindClass("java/util/Stack");
|
||||||
|
jmethodID constructor = env->GetMethodID(stack_class,"<init>", "()V");
|
||||||
|
jmethodID add = env->GetMethodID(stack_class, "push", "(Ljava/lang/Object;)Ljava/lang/Object;");
|
||||||
|
jobject our_stack = env->NewObject(stack_class, constructor);
|
||||||
|
for (std::basic_string_view<char> string: to_add) {
|
||||||
|
env->CallObjectMethod(our_stack, add, env->NewStringUTF(string.data()));
|
||||||
|
}
|
||||||
|
return our_stack;
|
||||||
|
}
|
||||||
|
|
||||||
jobject jlongFromOptional(JNIEnv* env, std::optional<long long> optional) {
|
jobject jlongFromOptional(JNIEnv* env, std::optional<long long> optional) {
|
||||||
if (!optional) {
|
if (!optional) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#define SESSION_ANDROID_UTIL_H
|
#define SESSION_ANDROID_UTIL_H
|
||||||
|
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <mutex>
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include "session/types.hpp"
|
#include "session/types.hpp"
|
||||||
|
@ -12,13 +11,6 @@
|
||||||
#include "session/config/profile_pic.hpp"
|
#include "session/config/profile_pic.hpp"
|
||||||
#include "session/config/user_groups.hpp"
|
#include "session/config/user_groups.hpp"
|
||||||
#include "session/config/expiring.hpp"
|
#include "session/config/expiring.hpp"
|
||||||
//#include <android/log.h>
|
|
||||||
|
|
||||||
//#define LOG_TAG "libsession-jni"
|
|
||||||
//#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
|
|
||||||
//#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
|
|
||||||
//#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
|
|
||||||
//#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
|
|
||||||
|
|
||||||
namespace util {
|
namespace util {
|
||||||
extern std::mutex util_mutex_;
|
extern std::mutex util_mutex_;
|
||||||
|
@ -37,6 +29,7 @@ namespace util {
|
||||||
jstring jstringFromOptional(JNIEnv* env, std::optional<std::string_view> optional);
|
jstring jstringFromOptional(JNIEnv* env, std::optional<std::string_view> optional);
|
||||||
jobject serialize_session_id(JNIEnv* env, std::string_view session_id);
|
jobject serialize_session_id(JNIEnv* env, std::string_view session_id);
|
||||||
std::string deserialize_session_id(JNIEnv* env, jobject session_id);
|
std::string deserialize_session_id(JNIEnv* env, jobject session_id);
|
||||||
|
jobject build_string_stack(JNIEnv* env, std::vector<std::string> to_add);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -57,11 +57,11 @@ sealed class ConfigBase(pointer: Long): Config(pointer) {
|
||||||
external fun dump(): ByteArray
|
external fun dump(): ByteArray
|
||||||
external fun encryptionDomain(): String
|
external fun encryptionDomain(): String
|
||||||
external fun confirmPushed(seqNo: Long, newHash: String)
|
external fun confirmPushed(seqNo: Long, newHash: String)
|
||||||
external fun merge(toMerge: Array<Pair<String,ByteArray>>): Int
|
external fun merge(toMerge: Array<Pair<String,ByteArray>>): Stack<String>
|
||||||
external fun currentHashes(): List<String>
|
external fun currentHashes(): List<String>
|
||||||
|
|
||||||
// Singular merge
|
// Singular merge
|
||||||
external fun merge(toMerge: Pair<String,ByteArray>): Int
|
external fun merge(toMerge: Pair<String,ByteArray>): Stack<String>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,7 +100,8 @@ class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long)
|
||||||
handleFailure(Error.NoSender, null)
|
handleFailure(Error.NoSender, null)
|
||||||
return
|
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:
|
// 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
|
// do not continue, but do not fail
|
||||||
handleFailure(Error.NoSender, null)
|
handleFailure(Error.NoSender, null)
|
||||||
|
|
|
@ -8,6 +8,7 @@ import kotlinx.coroutines.runBlocking
|
||||||
import nl.komponents.kovenant.Promise
|
import nl.komponents.kovenant.Promise
|
||||||
import nl.komponents.kovenant.task
|
import nl.komponents.kovenant.task
|
||||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
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.Message
|
||||||
import org.session.libsession.messaging.messages.control.CallMessage
|
import org.session.libsession.messaging.messages.control.CallMessage
|
||||||
import org.session.libsession.messaging.messages.control.ClosedGroupControlMessage
|
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.handleUnsendRequest
|
||||||
import org.session.libsession.messaging.sending_receiving.handleVisibleMessage
|
import org.session.libsession.messaging.sending_receiving.handleVisibleMessage
|
||||||
import org.session.libsession.messaging.utilities.Data
|
import org.session.libsession.messaging.utilities.Data
|
||||||
import org.session.libsignal.utilities.SessionId
|
|
||||||
import org.session.libsession.messaging.utilities.SodiumUtilities
|
import org.session.libsession.messaging.utilities.SodiumUtilities
|
||||||
import org.session.libsession.utilities.SSKEnvironment
|
import org.session.libsession.utilities.SSKEnvironment
|
||||||
import org.session.libsignal.protos.UtilProtos
|
import org.session.libsignal.protos.UtilProtos
|
||||||
import org.session.libsignal.utilities.IdPrefix
|
import org.session.libsignal.utilities.IdPrefix
|
||||||
import org.session.libsignal.utilities.Log
|
import org.session.libsignal.utilities.Log
|
||||||
|
import org.session.libsignal.utilities.SessionId
|
||||||
|
|
||||||
data class MessageReceiveParameters(
|
data class MessageReceiveParameters(
|
||||||
val data: ByteArray,
|
val data: ByteArray,
|
||||||
val serverHash: String? = null,
|
val serverHash: String? = null,
|
||||||
val openGroupMessageServerID: Long? = 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(
|
class BatchMessageReceiveJob(
|
||||||
|
@ -69,6 +71,7 @@ class BatchMessageReceiveJob(
|
||||||
private val SERVER_HASH_KEY = "serverHash"
|
private val SERVER_HASH_KEY = "serverHash"
|
||||||
private val OPEN_GROUP_MESSAGE_SERVER_ID_KEY = "openGroupMessageServerID"
|
private val OPEN_GROUP_MESSAGE_SERVER_ID_KEY = "openGroupMessageServerID"
|
||||||
private val OPEN_GROUP_ID_KEY = "open_group_id"
|
private val OPEN_GROUP_ID_KEY = "open_group_id"
|
||||||
|
private val CLOSED_GROUP_DESTINATION_KEY = "closed_group_destination"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun shouldCreateThread(parsedMessage: ParsedMessage): Boolean {
|
private fun shouldCreateThread(parsedMessage: ParsedMessage): Boolean {
|
||||||
|
@ -108,7 +111,13 @@ class BatchMessageReceiveJob(
|
||||||
messages.forEach { messageParameters ->
|
messages.forEach { messageParameters ->
|
||||||
val (data, serverHash, openGroupMessageServerID) = messageParameters
|
val (data, serverHash, openGroupMessageServerID) = messageParameters
|
||||||
try {
|
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
|
message.serverHash = serverHash
|
||||||
val parsedParams = ParsedMessage(messageParameters, message, proto)
|
val parsedParams = ParsedMessage(messageParameters, message, proto)
|
||||||
val threadID = Message.getThreadId(message, openGroupID, storage, shouldCreateThread(parsedParams)) ?: NO_THREAD_MAPPING
|
val threadID = Message.getThreadId(message, openGroupID, storage, shouldCreateThread(parsedParams)) ?: NO_THREAD_MAPPING
|
||||||
|
@ -262,12 +271,14 @@ class BatchMessageReceiveJob(
|
||||||
.build()
|
.build()
|
||||||
val serverHashes = messages.map { it.serverHash.orEmpty() }
|
val serverHashes = messages.map { it.serverHash.orEmpty() }
|
||||||
val openGroupServerIds = messages.map { it.openGroupMessageServerID ?: -1L }
|
val openGroupServerIds = messages.map { it.openGroupMessageServerID ?: -1L }
|
||||||
|
val closedGroups = messages.map { it.closedGroup?.publicKey.orEmpty() }
|
||||||
return Data.Builder()
|
return Data.Builder()
|
||||||
.putInt(NUM_MESSAGES_KEY, arraySize)
|
.putInt(NUM_MESSAGES_KEY, arraySize)
|
||||||
.putByteArray(DATA_KEY, dataArrays.toByteArray())
|
.putByteArray(DATA_KEY, dataArrays.toByteArray())
|
||||||
.putString(OPEN_GROUP_ID_KEY, openGroupID)
|
.putString(OPEN_GROUP_ID_KEY, openGroupID)
|
||||||
.putLongArray(OPEN_GROUP_MESSAGE_SERVER_ID_KEY, openGroupServerIds.toLongArray())
|
.putLongArray(OPEN_GROUP_MESSAGE_SERVER_ID_KEY, openGroupServerIds.toLongArray())
|
||||||
.putStringArray(SERVER_HASH_KEY, serverHashes.toTypedArray())
|
.putStringArray(SERVER_HASH_KEY, serverHashes.toTypedArray())
|
||||||
|
.putStringArray(CLOSED_GROUP_DESTINATION_KEY, closedGroups.toTypedArray())
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,11 +294,22 @@ class BatchMessageReceiveJob(
|
||||||
if (data.hasStringArray(SERVER_HASH_KEY)) data.getStringArray(SERVER_HASH_KEY) else arrayOf()
|
if (data.hasStringArray(SERVER_HASH_KEY)) data.getStringArray(SERVER_HASH_KEY) else arrayOf()
|
||||||
val openGroupMessageServerIDs = data.getLongArray(OPEN_GROUP_MESSAGE_SERVER_ID_KEY)
|
val openGroupMessageServerIDs = data.getLongArray(OPEN_GROUP_MESSAGE_SERVER_ID_KEY)
|
||||||
val openGroupID = data.getStringOrDefault(OPEN_GROUP_ID_KEY, null)
|
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 parameters = (0 until numMessages).map { index ->
|
||||||
val serverHash = serverHashes[index].let { if (it.isEmpty()) null else it }
|
val serverHash = serverHashes[index].let { if (it.isEmpty()) null else it }
|
||||||
val serverId = openGroupMessageServerIDs[index].let { if (it == -1L) 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)
|
return BatchMessageReceiveJob(parameters, openGroupID)
|
||||||
|
|
|
@ -17,6 +17,7 @@ import org.session.libsession.messaging.utilities.SodiumUtilities
|
||||||
import org.session.libsession.snode.SnodeAPI
|
import org.session.libsession.snode.SnodeAPI
|
||||||
import org.session.libsignal.crypto.PushTransportDetails
|
import org.session.libsignal.crypto.PushTransportDetails
|
||||||
import org.session.libsignal.protos.SignalServiceProtos
|
import org.session.libsignal.protos.SignalServiceProtos
|
||||||
|
import org.session.libsignal.protos.SignalServiceProtos.Envelope
|
||||||
import org.session.libsignal.utilities.IdPrefix
|
import org.session.libsignal.utilities.IdPrefix
|
||||||
import org.session.libsignal.utilities.Log
|
import org.session.libsignal.utilities.Log
|
||||||
import org.session.libsignal.utilities.SessionId
|
import org.session.libsignal.utilities.SessionId
|
||||||
|
@ -53,22 +54,24 @@ object MessageReceiver {
|
||||||
isOutgoing: Boolean? = null,
|
isOutgoing: Boolean? = null,
|
||||||
otherBlindedPublicKey: String? = null,
|
otherBlindedPublicKey: String? = null,
|
||||||
openGroupPublicKey: String? = null,
|
openGroupPublicKey: String? = null,
|
||||||
currentClosedGroups: Set<String>?
|
currentClosedGroups: Set<String>?,
|
||||||
|
closedGroupSessionId: String? = null,
|
||||||
): Pair<Message, SignalServiceProtos.Content> {
|
): Pair<Message, SignalServiceProtos.Content> {
|
||||||
val storage = MessagingModuleConfiguration.shared.storage
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
val userPublicKey = storage.getUserPublicKey()
|
val userPublicKey = storage.getUserPublicKey()
|
||||||
val isOpenGroupMessage = (openGroupServerID != null)
|
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 plaintext: ByteArray? = null
|
||||||
var sender: String? = null
|
var sender: String? = null
|
||||||
var groupPublicKey: 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) {
|
if (isOpenGroupMessage) {
|
||||||
plaintext = envelope.content.toByteArray()
|
plaintext = envelopeContent.toByteArray()
|
||||||
sender = envelope.source
|
sender = envelope.source
|
||||||
} else {
|
} else {
|
||||||
when (envelope.type) {
|
when (envelope.type) {
|
||||||
|
@ -77,7 +80,7 @@ object MessageReceiver {
|
||||||
openGroupPublicKey ?: throw Error.InvalidGroupPublicKey
|
openGroupPublicKey ?: throw Error.InvalidGroupPublicKey
|
||||||
otherBlindedPublicKey ?: throw Error.DecryptionFailed
|
otherBlindedPublicKey ?: throw Error.DecryptionFailed
|
||||||
val decryptionResult = MessageDecrypter.decryptBlinded(
|
val decryptionResult = MessageDecrypter.decryptBlinded(
|
||||||
ciphertext.toByteArray(),
|
envelopeContent.toByteArray(),
|
||||||
isOutgoing ?: false,
|
isOutgoing ?: false,
|
||||||
otherBlindedPublicKey,
|
otherBlindedPublicKey,
|
||||||
openGroupPublicKey
|
openGroupPublicKey
|
||||||
|
@ -86,26 +89,18 @@ object MessageReceiver {
|
||||||
sender = decryptionResult.second
|
sender = decryptionResult.second
|
||||||
} else {
|
} else {
|
||||||
val userX25519KeyPair = MessagingModuleConfiguration.shared.storage.getUserX25519KeyPair()
|
val userX25519KeyPair = MessagingModuleConfiguration.shared.storage.getUserX25519KeyPair()
|
||||||
val decryptionResult = MessageDecrypter.decrypt(ciphertext.toByteArray(), userX25519KeyPair)
|
val decryptionResult = MessageDecrypter.decrypt(envelopeContent.toByteArray(), userX25519KeyPair)
|
||||||
plaintext = decryptionResult.first
|
plaintext = decryptionResult.first
|
||||||
sender = decryptionResult.second
|
sender = decryptionResult.second
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SignalServiceProtos.Envelope.Type.CLOSED_GROUP_MESSAGE -> {
|
SignalServiceProtos.Envelope.Type.CLOSED_GROUP_MESSAGE -> {
|
||||||
val hexEncodedGroupPublicKey = envelope.source
|
val hexEncodedGroupPublicKey = closedGroupSessionId ?: envelope.source
|
||||||
val sessionId = SessionId.from(hexEncodedGroupPublicKey)
|
val sessionId = SessionId.from(hexEncodedGroupPublicKey)
|
||||||
if (sessionId.prefix == IdPrefix.GROUP) {
|
if (sessionId.prefix == IdPrefix.GROUP) {
|
||||||
val configFactory = MessagingModuleConfiguration.shared.configFactory
|
plaintext = envelopeContent.toByteArray()
|
||||||
configFactory.getGroupKeysConfig(sessionId)?.use { config ->
|
sender = envelope.source
|
||||||
config.decrypt(ciphertext.toByteArray())?.let { (decrypted, senderSessionId) ->
|
groupPublicKey = hexEncodedGroupPublicKey
|
||||||
plaintext = decrypted
|
|
||||||
sender = senderSessionId.hexString()
|
|
||||||
groupPublicKey = envelope.source
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (plaintext == null) {
|
|
||||||
throw Error.DecryptionFailed
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (!MessagingModuleConfiguration.shared.storage.isLegacyClosedGroup(hexEncodedGroupPublicKey)) {
|
if (!MessagingModuleConfiguration.shared.storage.isLegacyClosedGroup(hexEncodedGroupPublicKey)) {
|
||||||
throw Error.InvalidGroupPublicKey
|
throw Error.InvalidGroupPublicKey
|
||||||
|
@ -119,7 +114,7 @@ object MessageReceiver {
|
||||||
var encryptionKeyPair = encryptionKeyPairs.removeLast()
|
var encryptionKeyPair = encryptionKeyPairs.removeLast()
|
||||||
fun decrypt() {
|
fun decrypt() {
|
||||||
try {
|
try {
|
||||||
val decryptionResult = MessageDecrypter.decrypt(ciphertext.toByteArray(), encryptionKeyPair)
|
val decryptionResult = MessageDecrypter.decrypt(envelopeContent.toByteArray(), encryptionKeyPair)
|
||||||
plaintext = decryptionResult.first
|
plaintext = decryptionResult.first
|
||||||
sender = decryptionResult.second
|
sender = decryptionResult.second
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
@ -132,7 +127,7 @@ object MessageReceiver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
groupPublicKey = envelope.source
|
groupPublicKey = hexEncodedGroupPublicKey
|
||||||
decrypt()
|
decrypt()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,25 +125,8 @@ object MessageSender {
|
||||||
val proto = message.toProto() ?: throw Error.ProtoConversionFailed
|
val proto = message.toProto() ?: throw Error.ProtoConversionFailed
|
||||||
// Serialize the protobuf
|
// Serialize the protobuf
|
||||||
val plaintext = PushTransportDetails.getPaddedMessageBody(proto.toByteArray())
|
val plaintext = PushTransportDetails.getPaddedMessageBody(proto.toByteArray())
|
||||||
// Encrypt the serialized protobuf
|
|
||||||
val ciphertext = when (destination) {
|
// Envelope information
|
||||||
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
|
|
||||||
val kind: SignalServiceProtos.Envelope.Type
|
val kind: SignalServiceProtos.Envelope.Type
|
||||||
val senderPublicKey: String
|
val senderPublicKey: String
|
||||||
when (destination) {
|
when (destination) {
|
||||||
|
@ -161,7 +144,34 @@ object MessageSender {
|
||||||
}
|
}
|
||||||
else -> throw IllegalStateException("Destination should not be open group.")
|
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)
|
val base64EncodedData = Base64.encodeBytes(wrappedMessage)
|
||||||
// Send the result
|
// Send the result
|
||||||
return SnodeMessage(
|
return SnodeMessage(
|
||||||
|
|
|
@ -165,7 +165,7 @@ class ClosedGroupPoller(private val executor: CoroutineScope,
|
||||||
keysIndex -> handleKeyPoll(response, keys, info, members)
|
keysIndex -> handleKeyPoll(response, keys, info, members)
|
||||||
infoIndex -> handleInfo(response, info)
|
infoIndex -> handleInfo(response, info)
|
||||||
membersIndex -> handleMembers(response, members)
|
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 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) ->
|
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 ->
|
parameters.chunked(BatchMessageReceiveJob.BATCH_DEFAULT_NUMBER).forEach { chunk ->
|
||||||
val job = BatchMessageReceiveJob(chunk)
|
val job = BatchMessageReceiveJob(chunk)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package org.session.libsession.messaging.utilities
|
package org.session.libsession.messaging.utilities
|
||||||
|
|
||||||
import com.google.protobuf.ByteString
|
import com.google.protobuf.ByteString
|
||||||
import org.session.libsignal.utilities.Log
|
|
||||||
import org.session.libsignal.protos.SignalServiceProtos.Envelope
|
import org.session.libsignal.protos.SignalServiceProtos.Envelope
|
||||||
import org.session.libsignal.protos.WebSocketProtos.WebSocketMessage
|
import org.session.libsignal.protos.WebSocketProtos.WebSocketMessage
|
||||||
import org.session.libsignal.protos.WebSocketProtos.WebSocketRequestMessage
|
import org.session.libsignal.protos.WebSocketProtos.WebSocketRequestMessage
|
||||||
|
import org.session.libsignal.utilities.Log
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
|
|
||||||
object MessageWrapper {
|
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 {
|
try {
|
||||||
val builder = Envelope.newBuilder()
|
val builder = Envelope.newBuilder()
|
||||||
builder.type = type
|
builder.type = type
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.session.libsignal.utilities.Hex
|
||||||
import org.session.libsignal.utilities.JsonUtil
|
import org.session.libsignal.utilities.JsonUtil
|
||||||
import org.session.libsignal.utilities.Log
|
import org.session.libsignal.utilities.Log
|
||||||
import org.session.libsignal.utilities.Namespace
|
import org.session.libsignal.utilities.Namespace
|
||||||
|
import org.session.libsignal.utilities.SessionId
|
||||||
import org.session.libsignal.utilities.Snode
|
import org.session.libsignal.utilities.Snode
|
||||||
import org.session.libsignal.utilities.ThreadUtils
|
import org.session.libsignal.utilities.ThreadUtils
|
||||||
import org.session.libsignal.utilities.prettifiedDescription
|
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<*>
|
val messages = rawResponse["messages"] as? List<*>
|
||||||
return if (messages != null) {
|
return if (messages != null) {
|
||||||
if (updateLatestHash) {
|
if (updateLatestHash) {
|
||||||
updateLastMessageHashValueIfPossible(snode, publicKey, messages, namespace)
|
updateLastMessageHashValueIfPossible(snode, publicKey, messages, namespace)
|
||||||
}
|
}
|
||||||
val newRawMessages = removeDuplicates(publicKey, messages, namespace, updateStoredHashes)
|
val newRawMessages = removeDuplicates(publicKey, messages, namespace, updateStoredHashes)
|
||||||
return parseEnvelopes(newRawMessages)
|
return parseEnvelopes(newRawMessages, decrypt)
|
||||||
} else {
|
} else {
|
||||||
listOf()
|
listOf()
|
||||||
}
|
}
|
||||||
|
@ -895,14 +903,20 @@ object SnodeAPI {
|
||||||
return result
|
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 ->
|
return rawMessages.mapNotNull { rawMessage ->
|
||||||
val rawMessageAsJSON = rawMessage as? Map<*, *>
|
val rawMessageAsJSON = rawMessage as? Map<*, *>
|
||||||
val base64EncodedData = rawMessageAsJSON?.get("data") as? String
|
val base64EncodedData = rawMessageAsJSON?.get("data") as? String
|
||||||
val data = base64EncodedData?.let { Base64.decode(it) }
|
val data = base64EncodedData?.let { Base64.decode(it) }
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
try {
|
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) {
|
} catch (e: Exception) {
|
||||||
Log.d("Loki", "Failed to unwrap data for message: ${rawMessage.prettifiedDescription()}.")
|
Log.d("Loki", "Failed to unwrap data for message: ${rawMessage.prettifiedDescription()}.")
|
||||||
null
|
null
|
||||||
|
|
Loading…
Reference in a new issue