From 1819ad285af6c75adcb4832d497abbd8aa5a0797 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Thu, 28 Aug 2025 15:05:01 +1000 Subject: [PATCH 01/16] Add session protocol binding --- gradle/libs.versions.toml | 4 +- library/build.gradle.kts | 2 +- library/src/main/cpp/CMakeLists.txt | 1 + library/src/main/cpp/group_keys.cpp | 7 + library/src/main/cpp/jni_utils.h | 19 +- library/src/main/cpp/protocol.cpp | 325 ++++++++++++++++++ .../loki/messenger/libsession_util/Config.kt | 1 + .../libsession_util/GroupKeysConfig.kt | 1 + .../protocol/DecryptEnvelopeKey.kt | 22 ++ .../protocol/DecryptedEnvelope.kt | 26 ++ .../libsession_util/protocol/Destination.kt | 106 ++++++ .../libsession_util/protocol/ProFeatures.kt | 24 ++ .../libsession_util/protocol/ProStatus.kt | 22 ++ .../protocol/SessionProtocol.kt | 19 + libsession-util | 2 +- 15 files changed, 576 insertions(+), 5 deletions(-) create mode 100644 library/src/main/cpp/protocol.cpp create mode 100644 library/src/main/java/network/loki/messenger/libsession_util/protocol/DecryptEnvelopeKey.kt create mode 100644 library/src/main/java/network/loki/messenger/libsession_util/protocol/DecryptedEnvelope.kt create mode 100644 library/src/main/java/network/loki/messenger/libsession_util/protocol/Destination.kt create mode 100644 library/src/main/java/network/loki/messenger/libsession_util/protocol/ProFeatures.kt create mode 100644 library/src/main/java/network/loki/messenger/libsession_util/protocol/ProStatus.kt create mode 100644 library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 241dc78..e3f6a18 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] -agp = "8.12.0" -kotlin = "2.2.0" +agp = "8.12.1" +kotlin = "2.2.10" [libraries] junit = { module = "junit:junit", version = "4.13.2" } diff --git a/library/build.gradle.kts b/library/build.gradle.kts index 23ed558..1597fa6 100644 --- a/library/build.gradle.kts +++ b/library/build.gradle.kts @@ -12,7 +12,7 @@ android { compileSdk = 35 defaultConfig { - minSdk = 24 + minSdk = 26 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" diff --git a/library/src/main/cpp/CMakeLists.txt b/library/src/main/cpp/CMakeLists.txt index 8256a10..21863b0 100644 --- a/library/src/main/cpp/CMakeLists.txt +++ b/library/src/main/cpp/CMakeLists.txt @@ -44,6 +44,7 @@ set(SOURCES ed25519.cpp curve25519.cpp hash.cpp + protocol.cpp ) add_library( # Sets the name of the library. diff --git a/library/src/main/cpp/group_keys.cpp b/library/src/main/cpp/group_keys.cpp index 45f87f7..55f43bc 100644 --- a/library/src/main/cpp/group_keys.cpp +++ b/library/src/main/cpp/group_keys.cpp @@ -187,6 +187,13 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_keys(JNIEnv *env, j return jni_utils::jlist_from_collection(env, ptr->group_keys(), util::bytes_from_span); } +extern "C" +JNIEXPORT jobject JNICALL +Java_network_loki_messenger_libsession_1util_GroupKeysConfig_groupEncKey(JNIEnv *env, jobject thiz) { + auto ptr = ptrToKeys(env, thiz); + return util::bytes_from_span(env, ptr->group_enc_key()); +} + extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_GroupKeysConfig_activeHashes(JNIEnv *env, diff --git a/library/src/main/cpp/jni_utils.h b/library/src/main/cpp/jni_utils.h index 5aca809..45b0552 100644 --- a/library/src/main/cpp/jni_utils.h +++ b/library/src/main/cpp/jni_utils.h @@ -69,6 +69,11 @@ namespace jni_utils { env_->DeleteLocalRef(ref_); } } + JavaLocalRef(JavaLocalRef&& other) : env_(other.env_), ref_(other.ref_) { + other.ref_ = nullptr; + } + + JavaLocalRef(const JavaLocalRef&) = delete; inline JNIType get() const { return ref_; @@ -162,6 +167,8 @@ namespace jni_utils { data = std::span(const_cast(c_str), env->GetStringUTFLength(s)); } + JavaStringRef(const JavaStringRef &) = delete; + ~JavaStringRef() { env->ReleaseStringUTFChars(s, data.data()); } @@ -195,8 +202,18 @@ namespace jni_utils { data = std::span(reinterpret_cast(env->GetByteArrayElements(byte_array, nullptr)), length); } + JavaByteArrayRef(const JavaByteArrayRef &) = delete; + + JavaByteArrayRef(JavaByteArrayRef&& other) : env(other.env), byte_array(other.byte_array), data(other.data) { + other.byte_array = nullptr; + other.data = {}; + } + ~JavaByteArrayRef() { - env->ReleaseByteArrayElements(byte_array, reinterpret_cast(data.data()), 0); + if (byte_array) { + env->ReleaseByteArrayElements(byte_array, + reinterpret_cast(data.data()), 0); + } } // Get the data as a span. Only valid during the lifetime of this object. diff --git a/library/src/main/cpp/protocol.cpp b/library/src/main/cpp/protocol.cpp new file mode 100644 index 0000000..b9aaf85 --- /dev/null +++ b/library/src/main/cpp/protocol.cpp @@ -0,0 +1,325 @@ +#include +#include + +#include "jni_utils.h" + +using namespace jni_utils; + +template +static std::optional> java_to_cpp_array(JNIEnv *env, jbyteArray array) { + if (!array) { + return std::nullopt; + } + + JavaByteArrayRef bytes(env, array); + auto span = bytes.get(); + if (span.size() != N) { + throw std::runtime_error("Invalid byte array length from java, expecting " + std::to_string(N) + " got " + std::to_string(span.size())); + } + + std::array out; + std::copy(span.begin(), span.end(), out.begin()); + return out; +} + +extern "C" +JNIEXPORT void JNICALL +Java_network_loki_messenger_libsession_1util_protocol_Destination_00024Contact_toNativeDestination( + JNIEnv *env, jobject thiz, jlong native_ptr) { + auto &dest = *reinterpret_cast(native_ptr); + + JavaLocalRef clazz(env, env->GetObjectClass(thiz)); + + JavaLocalRef pub_key( + env, + reinterpret_cast(env->CallObjectMethod( + thiz, + env->GetMethodID(clazz.get(), "getRecipientPubKey", "()[B")))); + + JavaLocalRef sig( + env, + reinterpret_cast(env->CallObjectMethod( + thiz, + env->GetMethodID(clazz.get(), "getProSignature", "()[B")))); + jlong timestamp = env->CallLongMethod(thiz, env->GetMethodID(clazz.get(), "getSentTimestampMs", + "()J")); + + run_catching_cxx_exception_or_throws(env, [&] { + dest.type = session::DestinationType::Contact; + dest.pro_sig = java_to_cpp_array<64>(env, sig.get()); + dest.recipient_pubkey = java_to_cpp_array<33>(env, pub_key.get()).value(); + dest.sent_timestamp_ms = std::chrono::milliseconds{timestamp}; + }); +} + +extern "C" +JNIEXPORT void JNICALL +Java_network_loki_messenger_libsession_1util_protocol_Destination_00024Sync_toNativeDestination( + JNIEnv *env, jobject thiz, jlong native_ptr) { + auto &dest = *reinterpret_cast(native_ptr); + + JavaLocalRef clazz(env, env->GetObjectClass(thiz)); + + JavaLocalRef pub_key( + env, + reinterpret_cast(env->CallObjectMethod( + thiz, + env->GetMethodID(clazz.get(), "getMyPubKey", "()[B")))); + + JavaLocalRef sig( + env, + reinterpret_cast(env->CallObjectMethod( + thiz, + env->GetMethodID(clazz.get(), "getProSignature", "()[B")))); + jlong timestamp = env->CallLongMethod(thiz, env->GetMethodID(clazz.get(), "getSentTimestampMs", + "()J")); + + run_catching_cxx_exception_or_throws(env, [&] { + dest.type = session::DestinationType::SyncMessage; + dest.pro_sig = java_to_cpp_array<64>(env, sig.get()); + dest.recipient_pubkey = java_to_cpp_array<33>(env, pub_key.get()).value(); + dest.sent_timestamp_ms = std::chrono::milliseconds{timestamp}; + }); +} + +extern "C" +JNIEXPORT void JNICALL +Java_network_loki_messenger_libsession_1util_protocol_Destination_00024Group_toNativeDestination( + JNIEnv *env, jobject thiz, jlong native_ptr) { + auto &dest = *reinterpret_cast(native_ptr); + + JavaLocalRef clazz(env, env->GetObjectClass(thiz)); + + JavaLocalRef pub_key( + env, + reinterpret_cast(env->CallObjectMethod( + thiz, + env->GetMethodID(clazz.get(), "getEd25519PubKey", "()[B")))); + + JavaLocalRef priv_key( + env, + reinterpret_cast(env->CallObjectMethod( + thiz, + env->GetMethodID(clazz.get(), "getEd25519PrivKey", "()[B")))); + + JavaLocalRef sig( + env, + reinterpret_cast(env->CallObjectMethod( + thiz, + env->GetMethodID(clazz.get(), "getProSignature", "()[B")))); + + jlong timestamp = env->CallLongMethod(thiz, env->GetMethodID(clazz.get(), "getSentTimestampMs", + "()J")); + + run_catching_cxx_exception_or_throws(env, [&] { + dest.type = session::DestinationType::Group; + dest.pro_sig = java_to_cpp_array<64>(env, sig.get()); + dest.group_ed25519_privkey = java_to_cpp_array<32>(env, priv_key.get()).value(); + dest.group_ed25519_pubkey = java_to_cpp_array<33>(env, pub_key.get()).value(); + dest.sent_timestamp_ms = std::chrono::milliseconds{timestamp}; + }); +} + +extern "C" +JNIEXPORT void JNICALL +Java_network_loki_messenger_libsession_1util_protocol_Destination_00024Community_toNativeDestination( + JNIEnv *env, jobject thiz, jlong native_ptr) { + auto &dest = *reinterpret_cast(native_ptr); + + JavaLocalRef clazz(env, env->GetObjectClass(thiz)); + JavaLocalRef sig( + env, + reinterpret_cast(env->CallObjectMethod( + thiz, + env->GetMethodID(clazz.get(), "getProSignature", "()[B")))); + + jlong timestamp = env->CallLongMethod(thiz, env->GetMethodID(clazz.get(), "getSentTimestampMs", + "()J")); + + run_catching_cxx_exception_or_throws(env, [&] { + dest.type = session::DestinationType::Community; + dest.pro_sig = java_to_cpp_array<64>(env, sig.get()); + dest.sent_timestamp_ms = std::chrono::milliseconds{timestamp}; + }); +} + +extern "C" +JNIEXPORT void JNICALL +Java_network_loki_messenger_libsession_1util_protocol_Destination_00024CommunityInbox_toNativeDestination( + JNIEnv *env, jobject thiz, jlong native_ptr) { + auto &dest = *reinterpret_cast(native_ptr); + + JavaLocalRef clazz(env, env->GetObjectClass(thiz)); + + JavaLocalRef recipient_pub_key( + env, + reinterpret_cast(env->CallObjectMethod( + thiz, + env->GetMethodID(clazz.get(), "getRecipientPubKey", "()[B")))); + + + JavaLocalRef pub_key( + env, + reinterpret_cast(env->CallObjectMethod( + thiz, + env->GetMethodID(clazz.get(), "getCommunityPubKey", "()[B")))); + + JavaLocalRef sig( + env, + reinterpret_cast(env->CallObjectMethod( + thiz, + env->GetMethodID(clazz.get(), "getProSignature", "()[B")))); + + jlong timestamp = env->CallLongMethod(thiz, env->GetMethodID(clazz.get(), "getSentTimestampMs", + "()J")); + + run_catching_cxx_exception_or_throws(env, [&] { + dest.type = session::DestinationType::CommunityInbox; + dest.pro_sig = java_to_cpp_array<64>(env, sig.get()); + dest.community_inbox_server_pubkey = java_to_cpp_array<32>(env, pub_key.get()).value(); + dest.recipient_pubkey = java_to_cpp_array<33>(env, recipient_pub_key.get()).value(); + dest.sent_timestamp_ms = std::chrono::milliseconds{timestamp}; + }); +} + + +extern "C" +JNIEXPORT jbyteArray JNICALL +Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encryptForDestination( + JNIEnv *env, + jobject thiz, + jbyteArray java_message, + jbyteArray java_my_ed25519_privkey, + jobject java_destination, + jint java_namespace) { + session::Destination dest; + auto to_native_method = env->GetMethodID(env->GetObjectClass(java_destination), "toNativeDestination", "(J)V"); + env->CallVoidMethod(java_destination, to_native_method, reinterpret_cast(&dest)); + + // Make sure nothing went wrong in toNativeDestination + if (env->ExceptionCheck()) { + return nullptr; + } + + return run_catching_cxx_exception_or_throws(env, [&] { + auto result = session::encrypt_for_destination( + JavaByteArrayRef(env, java_message).get(), + JavaByteArrayRef(env, java_my_ed25519_privkey).get(), + dest, + static_cast(java_namespace)); + if (result.encrypted) { + return util::bytes_from_vector(env, result.ciphertext); + } else { + return (jbyteArray) nullptr; + } + }); +} + +static JavaLocalRef serializeProStatus(JNIEnv *env, const session::DecryptedEnvelope & envelope) { + if (!envelope.pro.has_value()) { + JavaLocalRef noneClass(env, env->FindClass("network/loki/messenger/libsession_util/protocol/ProStatus$None")); + auto fieldId = env->GetStaticFieldID( + noneClass.get(), + "INSTANCE", "Lnetwork/loki/messenger/libsession_util/protocol/ProStatus$None;"); + return JavaLocalRef(env, env->GetStaticObjectField(noneClass.get(), fieldId)); + } + + if (envelope.pro->status == session::config::ProStatus::Valid) { + JavaLocalRef validClass(env, env->FindClass("network/loki/messenger/libsession_util/protocol/ProStatus$Valid")); + auto init = env->GetMethodID(validClass.get(), "", "(JJ)V"); + return JavaLocalRef(env, env->NewObject(validClass.get(), init, + static_cast(envelope.pro->proof.expiry_unix_ts.time_since_epoch().count()), + static_cast(envelope.pro->features))); + } + + JavaLocalRef invalidClass(env, env->FindClass("network/loki/messenger/libsession_util/protocol/ProStatus$Invalid")); + auto fieldId = env->GetStaticFieldID( + invalidClass.get(), + "INSTANCE", "Lnetwork/loki/messenger/libsession_util/protocol/ProStatus$Invalid;"); + return JavaLocalRef(env, env->GetStaticObjectField(invalidClass.get(), fieldId)); +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decryptEnvelope(JNIEnv *env, + jobject thiz, + jobject java_key, + jbyteArray java_payload, + jlong now_epoch_seconds, + jbyteArray java_pro_backend_pub_key) { + + session::DecryptEnvelopeKey key; + + std::vector> privateKeysStorage; + + struct RegularStorage { + JavaLocalRef ed25519PrivKeyRef; + JavaByteArrayRef ed25519PrivKeyBytesRef; + }; + + struct GroupData { + JavaLocalRef groupPubKeyRef; + JavaByteArrayRef groupPubKeyBytesRef; + + std::vector, JavaByteArrayRef>> groupKeysRef; + }; + + std::optional regularStorage; + std::optional groupStorage; + + JavaLocalRef regularClazz(env, env->FindClass("network/loki/messenger/libsession_util/protocol/DecryptEnvelopeKey$Regular")); + if (env->IsInstanceOf(java_key, regularClazz.get())) { + auto bytes = reinterpret_cast(env->CallObjectMethod(java_key, env->GetMethodID(regularClazz.get(), "getEd25519PrivKey", "()[B"))); + regularStorage.emplace(RegularStorage { + .ed25519PrivKeyRef = JavaLocalRef(env, bytes), + .ed25519PrivKeyBytesRef = JavaByteArrayRef(env, bytes) + }); + + privateKeysStorage.push_back(regularStorage->ed25519PrivKeyBytesRef.get()); + } + + JavaLocalRef groupClazz(env, env->FindClass("network/loki/messenger/libsession_util/protocol/DecryptEnvelopeKey$Group")); + if (env->IsInstanceOf(java_key, groupClazz.get())) { + auto pubKeyBytes = reinterpret_cast(env->CallObjectMethod(java_key, env->GetMethodID(groupClazz.get(), "getGroupEd25519PubKey", "()[B"))); + groupStorage.emplace(GroupData { + .groupPubKeyRef = JavaLocalRef(env, pubKeyBytes), + .groupPubKeyBytesRef = JavaByteArrayRef(env, pubKeyBytes) + }); + + key.group_ed25519_pubkey.emplace(groupStorage->groupPubKeyBytesRef.get()); + + JavaLocalRef privKeyArrays(env, reinterpret_cast(env->CallObjectMethod(java_key, env->GetMethodID(groupClazz.get(), "getGroupKeys", "()[[B")))); + for (int i = 0, size = env->GetArrayLength(privKeyArrays.get()); i < size; i++) { + auto bytes = reinterpret_cast(env->GetObjectArrayElement(privKeyArrays.get(), i)); + const auto &last = groupStorage->groupKeysRef.emplace_back(JavaLocalRef(env, bytes), JavaByteArrayRef(env, bytes)); + privateKeysStorage.emplace_back(last.second.get()); + } + } + + key.ed25519_privkeys = { privateKeysStorage.data(), privateKeysStorage.size() }; + + return run_catching_cxx_exception_or_throws(env, [&] { + auto envelop = session::decrypt_envelope(key, JavaByteArrayRef(env, java_payload).get(), + std::chrono::sys_seconds { std::chrono::seconds { now_epoch_seconds } }, + *java_to_cpp_array<32>(env, java_pro_backend_pub_key)); + + JavaLocalRef sender_ed25519(env, util::bytes_from_span(env, envelop.sender_ed25519_pubkey)); + JavaLocalRef sender_x25519(env, util::bytes_from_span(env, envelop.sender_x25519_pubkey)); + JavaLocalRef content(env, util::bytes_from_vector(env, envelop.content_plaintext)); + + JavaLocalRef envelopClass(env, env->FindClass("network/loki/messenger/libsession_util/protocol/DecryptedEnvelope")); + jmethodID init = env->GetMethodID( + envelopClass.get(), + "", + "(Lnetwork/loki/messenger/libsession_util/protocol/ProStatus;[B[B[BJ)V" + ); + + return env->NewObject(envelopClass.get(), init, + serializeProStatus(env, envelop).get(), + content.get(), + sender_ed25519.get(), + sender_x25519.get(), + static_cast(envelop.envelope.timestamp.count())); + }); +} + diff --git a/library/src/main/java/network/loki/messenger/libsession_util/Config.kt b/library/src/main/java/network/loki/messenger/libsession_util/Config.kt index d177bf5..053ae71 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/Config.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/Config.kt @@ -221,6 +221,7 @@ sealed class ConfigSig(pointer: Long) : Config(pointer) interface ReadableGroupKeysConfig { fun groupKeys(): List + fun groupEncKey(): ByteArray fun needsDump(): Boolean fun dump(): ByteArray fun needsRekey(): Boolean diff --git a/library/src/main/java/network/loki/messenger/libsession_util/GroupKeysConfig.kt b/library/src/main/java/network/loki/messenger/libsession_util/GroupKeysConfig.kt index 4f7fff9..2970257 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/GroupKeysConfig.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/GroupKeysConfig.kt @@ -39,6 +39,7 @@ class GroupKeysConfig private constructor( override fun namespace() = Namespace.GROUP_KEYS() external override fun groupKeys(): List + external override fun groupEncKey(): ByteArray external override fun needsDump(): Boolean external override fun dump(): ByteArray external fun loadKey(message: ByteArray, diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecryptEnvelopeKey.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecryptEnvelopeKey.kt new file mode 100644 index 0000000..58de8fd --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecryptEnvelopeKey.kt @@ -0,0 +1,22 @@ +package network.loki.messenger.libsession_util.protocol + + +sealed interface DecryptEnvelopeKey { + + class Group( + val groupEd25519PubKey: ByteArray, + val groupKeys: Array + ) : DecryptEnvelopeKey { + constructor( + groupEd25519PubKey: ByteArray, + groupKeys: Collection + ) : this( + groupEd25519PubKey, + groupKeys.toTypedArray() + ) + } + + class Regular( + val ed25519PrivKey: ByteArray + ) : DecryptEnvelopeKey +} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecryptedEnvelope.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecryptedEnvelope.kt new file mode 100644 index 0000000..637af9a --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecryptedEnvelope.kt @@ -0,0 +1,26 @@ +package network.loki.messenger.libsession_util.protocol + +import network.loki.messenger.libsession_util.util.Bytes +import java.time.Instant + +data class DecryptedEnvelope( + val proStatus: ProStatus, + val contentPlainText: Bytes, + val senderEd25519PubKey: Bytes, + val senderX25519PubKey: Bytes, + val timestamp: Instant +) { + constructor( + proStatus: ProStatus, + contentPlainText: ByteArray, + senderEd25519PubKey: ByteArray, + senderX25519PubKey: ByteArray, + timestampEpochMills: Long + ): this( + proStatus = proStatus, + contentPlainText = Bytes(contentPlainText), + senderEd25519PubKey = Bytes(senderEd25519PubKey), + senderX25519PubKey = Bytes(senderX25519PubKey), + timestamp = Instant.ofEpochMilli(timestampEpochMills) + ) +} diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/Destination.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/Destination.kt new file mode 100644 index 0000000..fde0122 --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/Destination.kt @@ -0,0 +1,106 @@ +package network.loki.messenger.libsession_util.protocol + + +sealed interface Destination { + val proSignature: ByteArray? + val sentTimestampMs: Long + + fun toNativeDestination(nativePtr: Long) + + class Contact( + // 33 ByteArray prefixed key + val recipientPubKey: ByteArray, + override val proSignature: ByteArray?, + override val sentTimestampMs: Long + ) : Destination { + init { + check(recipientPubKey.size == 33) { + "recipientPubKey must be 33 ByteArray prefixed key" + } + + check(proSignature == null || proSignature.size == 64) { + "proSignature must be null or 64 ByteArray" + } + } + + external override fun toNativeDestination(nativePtr: Long) + } + + class Sync( + // 33 ByteArray prefixed key + val myPubKey: ByteArray, + override val proSignature: ByteArray?, + override val sentTimestampMs: Long + ) : Destination { + init { + check(myPubKey.size == 33) { + "myPubKey must be 33 ByteArray prefixed key" + } + + check(proSignature == null || proSignature.size == 64) { + "proSignature must be null or 64 ByteArray" + } + } + + external override fun toNativeDestination(nativePtr: Long) + } + + class Group( + val ed25519PubKey: ByteArray, + val ed25519PrivKey: ByteArray, + override val proSignature: ByteArray?, + override val sentTimestampMs: Long + ) : Destination { + init { + check(ed25519PubKey.size == 33) { + "groupPubKey must be 33 ByteArray unprefixed key" + } + + check(ed25519PrivKey.size == 32) { + "groupPrivKey must be 32 ByteArray unprefixed key" + } + + check(proSignature == null || proSignature.size == 64) { + "proSignature must be null or 64 ByteArray" + } + } + + external override fun toNativeDestination(nativePtr: Long) + } + + class Community( + override val proSignature: ByteArray?, + override val sentTimestampMs: Long + ) : Destination { + init { + check(proSignature == null || proSignature.size == 64) { + "proSignature must be null or 64 ByteArray" + } + } + + external override fun toNativeDestination(nativePtr: Long) + } + + class CommunityInbox( + val communityPubKey: ByteArray, + val recipientPubKey: ByteArray, + override val proSignature: ByteArray?, + override val sentTimestampMs: Long + ) : Destination { + init { + check(communityPubKey.size == 33) { + "communityInboxPubKey must be 33 ByteArray unprefixed key" + } + + check(recipientPubKey.size == 33) { + "recipientPubKey must be 33 ByteArray prefixed key" + } + + check(proSignature == null || proSignature.size == 64) { + "proSignature must be null or 64 ByteArray" + } + } + + external override fun toNativeDestination(nativePtr: Long) + } +} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProFeatures.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProFeatures.kt new file mode 100644 index 0000000..843be42 --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProFeatures.kt @@ -0,0 +1,24 @@ +package network.loki.messenger.libsession_util.protocol + + +enum class ProFeature(internal val bitIndex: Int) { + HIGHER_CHARACTER_LIMIT(0), + PRO_BADGE(1), + ANIMATED_AVATAR(2), +} + +internal fun Long.toFeatures(): Set { + return buildSet(ProFeature.entries.size) { + for (entry in ProFeature.entries) { + if (this@toFeatures and (1L shl entry.bitIndex) != 0L) { + add(entry) + } + } + } +} + +internal fun Collection.toLong(): Long { + return fold(0L) { acc, entry -> + acc or (1L shl entry.bitIndex) + } +} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProStatus.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProStatus.kt new file mode 100644 index 0000000..bf53bb8 --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProStatus.kt @@ -0,0 +1,22 @@ +package network.loki.messenger.libsession_util.protocol + +import java.time.Instant + + +sealed interface ProStatus { + data object None : ProStatus + data object Invalid : ProStatus + + data class Valid( + val expiresAt: Instant, + val proFeatures: Set + ) { + constructor( + expiresAtEpochSeconds: Long, + proFeatures: Long + ): this( + expiresAt = Instant.ofEpochSecond(expiresAtEpochSeconds), + proFeatures = proFeatures.toFeatures() + ) + } +} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt new file mode 100644 index 0000000..09befae --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt @@ -0,0 +1,19 @@ +package network.loki.messenger.libsession_util.protocol + +import network.loki.messenger.libsession_util.LibSessionUtilCApi + +object SessionProtocol : LibSessionUtilCApi() { + external fun encryptForDestination( + message: ByteArray, + myEd25519PrivKey: ByteArray, + destination: Destination, + namespace: Int + ): ByteArray? + + external fun decryptEnvelope( + key: DecryptEnvelopeKey, + payload: ByteArray, + nowEpochSeconds: Long, + proBackendPubKey: ByteArray, // 32 bytes backend key + ): DecryptedEnvelope +} \ No newline at end of file diff --git a/libsession-util b/libsession-util index 3ee705f..c310e57 160000 --- a/libsession-util +++ b/libsession-util @@ -1 +1 @@ -Subproject commit 3ee705f3248337c71c159a88f6baafe85c02f1c3 +Subproject commit c310e576965311e84e32dd37f0908275110019ca From d4898ab95e4644a20bf1991e20a184bef389aa41 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Fri, 29 Aug 2025 16:09:13 +1000 Subject: [PATCH 02/16] Update libsession's protocol encryption API --- library/src/main/cpp/jni_utils.h | 19 ++ library/src/main/cpp/protocol.cpp | 288 +++++------------- .../libsession_util/protocol/Destination.kt | 106 ------- .../protocol/SessionProtocol.kt | 29 +- libsession-util | 2 +- 5 files changed, 120 insertions(+), 324 deletions(-) delete mode 100644 library/src/main/java/network/loki/messenger/libsession_util/protocol/Destination.kt diff --git a/library/src/main/cpp/jni_utils.h b/library/src/main/cpp/jni_utils.h index 45b0552..a9cc6f5 100644 --- a/library/src/main/cpp/jni_utils.h +++ b/library/src/main/cpp/jni_utils.h @@ -80,6 +80,7 @@ namespace jni_utils { } }; + /** * Create a Java List from an iterator. * @@ -225,6 +226,24 @@ namespace jni_utils { return std::vector(data.begin(), data.end()); } }; + + template + static std::optional> java_to_cpp_array(JNIEnv *env, jbyteArray array) { + if (!array) { + return std::nullopt; + } + + JavaByteArrayRef bytes(env, array); + auto span = bytes.get(); + if (span.size() != N) { + throw std::runtime_error("Invalid byte array length from java, expecting " + std::to_string(N) + " got " + std::to_string(span.size())); + } + + std::array out; + std::copy(span.begin(), span.end(), out.begin()); + return out; + } + } #endif //SESSION_ANDROID_JNI_UTILS_H diff --git a/library/src/main/cpp/protocol.cpp b/library/src/main/cpp/protocol.cpp index b9aaf85..68fb27c 100644 --- a/library/src/main/cpp/protocol.cpp +++ b/library/src/main/cpp/protocol.cpp @@ -1,219 +1,12 @@ #include #include +#include #include "jni_utils.h" using namespace jni_utils; -template -static std::optional> java_to_cpp_array(JNIEnv *env, jbyteArray array) { - if (!array) { - return std::nullopt; - } - - JavaByteArrayRef bytes(env, array); - auto span = bytes.get(); - if (span.size() != N) { - throw std::runtime_error("Invalid byte array length from java, expecting " + std::to_string(N) + " got " + std::to_string(span.size())); - } - - std::array out; - std::copy(span.begin(), span.end(), out.begin()); - return out; -} - -extern "C" -JNIEXPORT void JNICALL -Java_network_loki_messenger_libsession_1util_protocol_Destination_00024Contact_toNativeDestination( - JNIEnv *env, jobject thiz, jlong native_ptr) { - auto &dest = *reinterpret_cast(native_ptr); - - JavaLocalRef clazz(env, env->GetObjectClass(thiz)); - - JavaLocalRef pub_key( - env, - reinterpret_cast(env->CallObjectMethod( - thiz, - env->GetMethodID(clazz.get(), "getRecipientPubKey", "()[B")))); - - JavaLocalRef sig( - env, - reinterpret_cast(env->CallObjectMethod( - thiz, - env->GetMethodID(clazz.get(), "getProSignature", "()[B")))); - jlong timestamp = env->CallLongMethod(thiz, env->GetMethodID(clazz.get(), "getSentTimestampMs", - "()J")); - run_catching_cxx_exception_or_throws(env, [&] { - dest.type = session::DestinationType::Contact; - dest.pro_sig = java_to_cpp_array<64>(env, sig.get()); - dest.recipient_pubkey = java_to_cpp_array<33>(env, pub_key.get()).value(); - dest.sent_timestamp_ms = std::chrono::milliseconds{timestamp}; - }); -} - -extern "C" -JNIEXPORT void JNICALL -Java_network_loki_messenger_libsession_1util_protocol_Destination_00024Sync_toNativeDestination( - JNIEnv *env, jobject thiz, jlong native_ptr) { - auto &dest = *reinterpret_cast(native_ptr); - - JavaLocalRef clazz(env, env->GetObjectClass(thiz)); - - JavaLocalRef pub_key( - env, - reinterpret_cast(env->CallObjectMethod( - thiz, - env->GetMethodID(clazz.get(), "getMyPubKey", "()[B")))); - - JavaLocalRef sig( - env, - reinterpret_cast(env->CallObjectMethod( - thiz, - env->GetMethodID(clazz.get(), "getProSignature", "()[B")))); - jlong timestamp = env->CallLongMethod(thiz, env->GetMethodID(clazz.get(), "getSentTimestampMs", - "()J")); - - run_catching_cxx_exception_or_throws(env, [&] { - dest.type = session::DestinationType::SyncMessage; - dest.pro_sig = java_to_cpp_array<64>(env, sig.get()); - dest.recipient_pubkey = java_to_cpp_array<33>(env, pub_key.get()).value(); - dest.sent_timestamp_ms = std::chrono::milliseconds{timestamp}; - }); -} - -extern "C" -JNIEXPORT void JNICALL -Java_network_loki_messenger_libsession_1util_protocol_Destination_00024Group_toNativeDestination( - JNIEnv *env, jobject thiz, jlong native_ptr) { - auto &dest = *reinterpret_cast(native_ptr); - - JavaLocalRef clazz(env, env->GetObjectClass(thiz)); - - JavaLocalRef pub_key( - env, - reinterpret_cast(env->CallObjectMethod( - thiz, - env->GetMethodID(clazz.get(), "getEd25519PubKey", "()[B")))); - - JavaLocalRef priv_key( - env, - reinterpret_cast(env->CallObjectMethod( - thiz, - env->GetMethodID(clazz.get(), "getEd25519PrivKey", "()[B")))); - - JavaLocalRef sig( - env, - reinterpret_cast(env->CallObjectMethod( - thiz, - env->GetMethodID(clazz.get(), "getProSignature", "()[B")))); - - jlong timestamp = env->CallLongMethod(thiz, env->GetMethodID(clazz.get(), "getSentTimestampMs", - "()J")); - - run_catching_cxx_exception_or_throws(env, [&] { - dest.type = session::DestinationType::Group; - dest.pro_sig = java_to_cpp_array<64>(env, sig.get()); - dest.group_ed25519_privkey = java_to_cpp_array<32>(env, priv_key.get()).value(); - dest.group_ed25519_pubkey = java_to_cpp_array<33>(env, pub_key.get()).value(); - dest.sent_timestamp_ms = std::chrono::milliseconds{timestamp}; - }); -} - -extern "C" -JNIEXPORT void JNICALL -Java_network_loki_messenger_libsession_1util_protocol_Destination_00024Community_toNativeDestination( - JNIEnv *env, jobject thiz, jlong native_ptr) { - auto &dest = *reinterpret_cast(native_ptr); - - JavaLocalRef clazz(env, env->GetObjectClass(thiz)); - JavaLocalRef sig( - env, - reinterpret_cast(env->CallObjectMethod( - thiz, - env->GetMethodID(clazz.get(), "getProSignature", "()[B")))); - - jlong timestamp = env->CallLongMethod(thiz, env->GetMethodID(clazz.get(), "getSentTimestampMs", - "()J")); - - run_catching_cxx_exception_or_throws(env, [&] { - dest.type = session::DestinationType::Community; - dest.pro_sig = java_to_cpp_array<64>(env, sig.get()); - dest.sent_timestamp_ms = std::chrono::milliseconds{timestamp}; - }); -} - -extern "C" -JNIEXPORT void JNICALL -Java_network_loki_messenger_libsession_1util_protocol_Destination_00024CommunityInbox_toNativeDestination( - JNIEnv *env, jobject thiz, jlong native_ptr) { - auto &dest = *reinterpret_cast(native_ptr); - - JavaLocalRef clazz(env, env->GetObjectClass(thiz)); - - JavaLocalRef recipient_pub_key( - env, - reinterpret_cast(env->CallObjectMethod( - thiz, - env->GetMethodID(clazz.get(), "getRecipientPubKey", "()[B")))); - - - JavaLocalRef pub_key( - env, - reinterpret_cast(env->CallObjectMethod( - thiz, - env->GetMethodID(clazz.get(), "getCommunityPubKey", "()[B")))); - - JavaLocalRef sig( - env, - reinterpret_cast(env->CallObjectMethod( - thiz, - env->GetMethodID(clazz.get(), "getProSignature", "()[B")))); - - jlong timestamp = env->CallLongMethod(thiz, env->GetMethodID(clazz.get(), "getSentTimestampMs", - "()J")); - - run_catching_cxx_exception_or_throws(env, [&] { - dest.type = session::DestinationType::CommunityInbox; - dest.pro_sig = java_to_cpp_array<64>(env, sig.get()); - dest.community_inbox_server_pubkey = java_to_cpp_array<32>(env, pub_key.get()).value(); - dest.recipient_pubkey = java_to_cpp_array<33>(env, recipient_pub_key.get()).value(); - dest.sent_timestamp_ms = std::chrono::milliseconds{timestamp}; - }); -} - - -extern "C" -JNIEXPORT jbyteArray JNICALL -Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encryptForDestination( - JNIEnv *env, - jobject thiz, - jbyteArray java_message, - jbyteArray java_my_ed25519_privkey, - jobject java_destination, - jint java_namespace) { - session::Destination dest; - auto to_native_method = env->GetMethodID(env->GetObjectClass(java_destination), "toNativeDestination", "(J)V"); - env->CallVoidMethod(java_destination, to_native_method, reinterpret_cast(&dest)); - - // Make sure nothing went wrong in toNativeDestination - if (env->ExceptionCheck()) { - return nullptr; - } - - return run_catching_cxx_exception_or_throws(env, [&] { - auto result = session::encrypt_for_destination( - JavaByteArrayRef(env, java_message).get(), - JavaByteArrayRef(env, java_my_ed25519_privkey).get(), - dest, - static_cast(java_namespace)); - if (result.encrypted) { - return util::bytes_from_vector(env, result.ciphertext); - } else { - return (jbyteArray) nullptr; - } - }); -} static JavaLocalRef serializeProStatus(JNIEnv *env, const session::DecryptedEnvelope & envelope) { if (!envelope.pro.has_value()) { @@ -221,22 +14,22 @@ static JavaLocalRef serializeProStatus(JNIEnv *env, const session::Decr auto fieldId = env->GetStaticFieldID( noneClass.get(), "INSTANCE", "Lnetwork/loki/messenger/libsession_util/protocol/ProStatus$None;"); - return JavaLocalRef(env, env->GetStaticObjectField(noneClass.get(), fieldId)); + return {env, env->GetStaticObjectField(noneClass.get(), fieldId)}; } if (envelope.pro->status == session::config::ProStatus::Valid) { JavaLocalRef validClass(env, env->FindClass("network/loki/messenger/libsession_util/protocol/ProStatus$Valid")); auto init = env->GetMethodID(validClass.get(), "", "(JJ)V"); - return JavaLocalRef(env, env->NewObject(validClass.get(), init, + return {env, env->NewObject(validClass.get(), init, static_cast(envelope.pro->proof.expiry_unix_ts.time_since_epoch().count()), - static_cast(envelope.pro->features))); + static_cast(envelope.pro->features))}; } JavaLocalRef invalidClass(env, env->FindClass("network/loki/messenger/libsession_util/protocol/ProStatus$Invalid")); auto fieldId = env->GetStaticFieldID( invalidClass.get(), "INSTANCE", "Lnetwork/loki/messenger/libsession_util/protocol/ProStatus$Invalid;"); - return JavaLocalRef(env, env->GetStaticObjectField(invalidClass.get(), fieldId)); + return {env, env->GetStaticObjectField(invalidClass.get(), fieldId)}; } extern "C" @@ -323,3 +116,74 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decryptEnv }); } + +extern "C" +JNIEXPORT jbyteArray JNICALL +Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encryptFor1o1(JNIEnv *env, + jobject thiz, + jbyteArray plaintext, + jbyteArray my_ed25519_priv_key, + jlong timestamp_ms, + jbyteArray recipient_pub_key, + jbyteArray pro_signature) { + return run_catching_cxx_exception_or_throws(env, [=] { + return util::bytes_from_vector( + env, + session::encrypt_for_1o1( + JavaByteArrayRef(env, plaintext).get(), + JavaByteArrayRef(env, my_ed25519_priv_key).get(), + std::chrono::milliseconds { timestamp_ms }, + *java_to_cpp_array<33>(env, recipient_pub_key), + java_to_cpp_array<64>(env, pro_signature) + )); + }); +} + +extern "C" +JNIEXPORT jbyteArray JNICALL +Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encryptForCommunityInbox( + JNIEnv *env, jobject thiz, jbyteArray plaintext, jbyteArray my_ed25519_priv_key, + jlong timestamp_ms, jbyteArray recipient_pub_key, jbyteArray community_server_pub_key, + jbyteArray pro_signature) { + return run_catching_cxx_exception_or_throws(env, [=] { + return util::bytes_from_vector( + env, + session::encrypt_for_community_inbox( + JavaByteArrayRef(env, plaintext).get(), + JavaByteArrayRef(env, my_ed25519_priv_key).get(), + std::chrono::milliseconds { timestamp_ms }, + *java_to_cpp_array<33>(env, recipient_pub_key), + *java_to_cpp_array<32>(env, community_server_pub_key), + java_to_cpp_array<64>(env, pro_signature) + )); + }); +} + +extern "C" +JNIEXPORT jbyteArray JNICALL +Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encryptForGroup(JNIEnv *env, + jobject thiz, + jbyteArray plaintext, + jbyteArray my_ed25519_priv_key, + jlong timestamp_ms, + jbyteArray group_ed25519_public_key, + jbyteArray group_ed25519_private_key, + jbyteArray pro_signature) { + return run_catching_cxx_exception_or_throws(env, [=] { + session::cleared_uc32 group_private_key; + + auto array = *java_to_cpp_array<32>(env, group_ed25519_private_key); + std::copy(array.begin(), array.end(), group_private_key.begin()); + + return util::bytes_from_vector( + env, + session::encrypt_for_group( + JavaByteArrayRef(env, plaintext).get(), + JavaByteArrayRef(env, my_ed25519_priv_key).get(), + std::chrono::milliseconds { timestamp_ms }, + *java_to_cpp_array<33>(env, group_ed25519_public_key), + group_private_key, + java_to_cpp_array<64>(env, pro_signature) + )); + }); +} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/Destination.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/Destination.kt deleted file mode 100644 index fde0122..0000000 --- a/library/src/main/java/network/loki/messenger/libsession_util/protocol/Destination.kt +++ /dev/null @@ -1,106 +0,0 @@ -package network.loki.messenger.libsession_util.protocol - - -sealed interface Destination { - val proSignature: ByteArray? - val sentTimestampMs: Long - - fun toNativeDestination(nativePtr: Long) - - class Contact( - // 33 ByteArray prefixed key - val recipientPubKey: ByteArray, - override val proSignature: ByteArray?, - override val sentTimestampMs: Long - ) : Destination { - init { - check(recipientPubKey.size == 33) { - "recipientPubKey must be 33 ByteArray prefixed key" - } - - check(proSignature == null || proSignature.size == 64) { - "proSignature must be null or 64 ByteArray" - } - } - - external override fun toNativeDestination(nativePtr: Long) - } - - class Sync( - // 33 ByteArray prefixed key - val myPubKey: ByteArray, - override val proSignature: ByteArray?, - override val sentTimestampMs: Long - ) : Destination { - init { - check(myPubKey.size == 33) { - "myPubKey must be 33 ByteArray prefixed key" - } - - check(proSignature == null || proSignature.size == 64) { - "proSignature must be null or 64 ByteArray" - } - } - - external override fun toNativeDestination(nativePtr: Long) - } - - class Group( - val ed25519PubKey: ByteArray, - val ed25519PrivKey: ByteArray, - override val proSignature: ByteArray?, - override val sentTimestampMs: Long - ) : Destination { - init { - check(ed25519PubKey.size == 33) { - "groupPubKey must be 33 ByteArray unprefixed key" - } - - check(ed25519PrivKey.size == 32) { - "groupPrivKey must be 32 ByteArray unprefixed key" - } - - check(proSignature == null || proSignature.size == 64) { - "proSignature must be null or 64 ByteArray" - } - } - - external override fun toNativeDestination(nativePtr: Long) - } - - class Community( - override val proSignature: ByteArray?, - override val sentTimestampMs: Long - ) : Destination { - init { - check(proSignature == null || proSignature.size == 64) { - "proSignature must be null or 64 ByteArray" - } - } - - external override fun toNativeDestination(nativePtr: Long) - } - - class CommunityInbox( - val communityPubKey: ByteArray, - val recipientPubKey: ByteArray, - override val proSignature: ByteArray?, - override val sentTimestampMs: Long - ) : Destination { - init { - check(communityPubKey.size == 33) { - "communityInboxPubKey must be 33 ByteArray unprefixed key" - } - - check(recipientPubKey.size == 33) { - "recipientPubKey must be 33 ByteArray prefixed key" - } - - check(proSignature == null || proSignature.size == 64) { - "proSignature must be null or 64 ByteArray" - } - } - - external override fun toNativeDestination(nativePtr: Long) - } -} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt index 09befae..8de9a48 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt @@ -3,12 +3,31 @@ package network.loki.messenger.libsession_util.protocol import network.loki.messenger.libsession_util.LibSessionUtilCApi object SessionProtocol : LibSessionUtilCApi() { - external fun encryptForDestination( - message: ByteArray, + external fun encryptFor1o1( + plaintext: ByteArray, myEd25519PrivKey: ByteArray, - destination: Destination, - namespace: Int - ): ByteArray? + timestampMs: Long, + recipientPubKey: ByteArray, // 33 bytes prefixed key + proSignature: ByteArray?, // 64 bytes + ): ByteArray + + external fun encryptForCommunityInbox( + plaintext: ByteArray, + myEd25519PrivKey: ByteArray, + timestampMs: Long, + recipientPubKey: ByteArray, // 33 bytes prefixed key + communityServerPubKey: ByteArray, // 32 bytes key + proSignature: ByteArray?, // 64 bytes + ): ByteArray + + external fun encryptForGroup( + plaintext: ByteArray, + myEd25519PrivKey: ByteArray, + timestampMs: Long, + groupEd25519PublicKey: ByteArray, // 33 bytes 03 prefixed key + groupEd25519PrivateKey: ByteArray, // 32 bytes group "encryption" key + proSignature: ByteArray?, // 64 bytes + ): ByteArray external fun decryptEnvelope( key: DecryptEnvelopeKey, diff --git a/libsession-util b/libsession-util index c310e57..e0ec4c1 160000 --- a/libsession-util +++ b/libsession-util @@ -1 +1 @@ -Subproject commit c310e576965311e84e32dd37f0908275110019ca +Subproject commit e0ec4c198ba003acf95f96e29e2e855b8ae3fad5 From 37033b0cabfc70c01294f7d0cd2ccccecbd4d944 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Thu, 25 Sep 2025 14:43:50 +0800 Subject: [PATCH 03/16] Updated to latest libsession-util --- gradle/libs.versions.toml | 1 + library/build.gradle.kts | 2 ++ library/src/main/cpp/protocol.cpp | 2 +- .../messenger/libsession_util/protocol/DecryptedEnvelope.kt | 2 ++ .../loki/messenger/libsession_util/protocol/ProStatus.kt | 2 ++ libsession-util | 2 +- 6 files changed, 9 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 27ba1cf..69add3c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,6 +7,7 @@ junit = { module = "junit:junit", version = "4.13.2" } androidx-test-runner = { module = "androidx.test:runner", version = "1.7.0" } androidx-test-rules = { module = "androidx.test:rules", version = "1.7.0" } androidx-test-ext = { module = "androidx.test.ext:junit", version = "1.3.0" } +androidx-annotations = { module = "androidx.annotation:annotation", version = "1.9.1" } [plugins] android-library = { id = "com.android.library", version.ref = "agp" } diff --git a/library/build.gradle.kts b/library/build.gradle.kts index 7c4778a..cc20c87 100644 --- a/library/build.gradle.kts +++ b/library/build.gradle.kts @@ -102,4 +102,6 @@ dependencies { androidTestImplementation(libs.androidx.test.runner) androidTestImplementation(libs.androidx.test.rules) androidTestImplementation(libs.androidx.test.ext) + + implementation(libs.androidx.annotations) } diff --git a/library/src/main/cpp/protocol.cpp b/library/src/main/cpp/protocol.cpp index 68fb27c..7ce4f60 100644 --- a/library/src/main/cpp/protocol.cpp +++ b/library/src/main/cpp/protocol.cpp @@ -17,7 +17,7 @@ static JavaLocalRef serializeProStatus(JNIEnv *env, const session::Decr return {env, env->GetStaticObjectField(noneClass.get(), fieldId)}; } - if (envelope.pro->status == session::config::ProStatus::Valid) { + if (envelope.pro->status == session::ProStatus::Valid) { JavaLocalRef validClass(env, env->FindClass("network/loki/messenger/libsession_util/protocol/ProStatus$Valid")); auto init = env->GetMethodID(validClass.get(), "", "(JJ)V"); return {env, env->NewObject(validClass.get(), init, diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecryptedEnvelope.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecryptedEnvelope.kt index 637af9a..26ef94b 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecryptedEnvelope.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecryptedEnvelope.kt @@ -1,5 +1,6 @@ package network.loki.messenger.libsession_util.protocol +import androidx.annotation.Keep import network.loki.messenger.libsession_util.util.Bytes import java.time.Instant @@ -10,6 +11,7 @@ data class DecryptedEnvelope( val senderX25519PubKey: Bytes, val timestamp: Instant ) { + @Keep constructor( proStatus: ProStatus, contentPlainText: ByteArray, diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProStatus.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProStatus.kt index bf53bb8..01b220e 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProStatus.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProStatus.kt @@ -1,5 +1,6 @@ package network.loki.messenger.libsession_util.protocol +import androidx.annotation.Keep import java.time.Instant @@ -11,6 +12,7 @@ sealed interface ProStatus { val expiresAt: Instant, val proFeatures: Set ) { + @Keep constructor( expiresAtEpochSeconds: Long, proFeatures: Long diff --git a/libsession-util b/libsession-util index c73fd92..db2e063 160000 --- a/libsession-util +++ b/libsession-util @@ -1 +1 @@ -Subproject commit c73fd92eb71e8108cc435fc640fbcb8faceacbb0 +Subproject commit db2e063cd73715433a0466c6219671b2c460addf From a1ded2b5965fea12e163521d95c8aa4ab6e61224 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Tue, 30 Sep 2025 10:41:08 +0800 Subject: [PATCH 04/16] Update to latest changes --- library/src/main/cpp/protocol.cpp | 24 +++++++++---------- .../protocol/SessionProtocol.kt | 6 ++--- libsession-util | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/library/src/main/cpp/protocol.cpp b/library/src/main/cpp/protocol.cpp index 7ce4f60..eeccce2 100644 --- a/library/src/main/cpp/protocol.cpp +++ b/library/src/main/cpp/protocol.cpp @@ -8,7 +8,7 @@ using namespace jni_utils; -static JavaLocalRef serializeProStatus(JNIEnv *env, const session::DecryptedEnvelope & envelope) { +static JavaLocalRef serializeProStatus(JNIEnv *env, const session::DecodedEnvelope & envelope) { if (!envelope.pro.has_value()) { JavaLocalRef noneClass(env, env->FindClass("network/loki/messenger/libsession_util/protocol/ProStatus$None")); auto fieldId = env->GetStaticFieldID( @@ -41,7 +41,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decryptEnv jlong now_epoch_seconds, jbyteArray java_pro_backend_pub_key) { - session::DecryptEnvelopeKey key; + session::DecodeEnvelopeKey key; std::vector> privateKeysStorage; @@ -92,7 +92,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decryptEnv key.ed25519_privkeys = { privateKeysStorage.data(), privateKeysStorage.size() }; return run_catching_cxx_exception_or_throws(env, [&] { - auto envelop = session::decrypt_envelope(key, JavaByteArrayRef(env, java_payload).get(), + auto envelop = session::decode_envelope(key, JavaByteArrayRef(env, java_payload).get(), std::chrono::sys_seconds { std::chrono::seconds { now_epoch_seconds } }, *java_to_cpp_array<32>(env, java_pro_backend_pub_key)); @@ -125,16 +125,16 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encryptFor jbyteArray my_ed25519_priv_key, jlong timestamp_ms, jbyteArray recipient_pub_key, - jbyteArray pro_signature) { + jbyteArray rotating_key) { return run_catching_cxx_exception_or_throws(env, [=] { return util::bytes_from_vector( env, - session::encrypt_for_1o1( + session::encode_for_1o1( JavaByteArrayRef(env, plaintext).get(), JavaByteArrayRef(env, my_ed25519_priv_key).get(), std::chrono::milliseconds { timestamp_ms }, *java_to_cpp_array<33>(env, recipient_pub_key), - java_to_cpp_array<64>(env, pro_signature) + rotating_key ? JavaByteArrayRef(env, rotating_key).get() : std::span() )); }); } @@ -144,17 +144,17 @@ JNIEXPORT jbyteArray JNICALL Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encryptForCommunityInbox( JNIEnv *env, jobject thiz, jbyteArray plaintext, jbyteArray my_ed25519_priv_key, jlong timestamp_ms, jbyteArray recipient_pub_key, jbyteArray community_server_pub_key, - jbyteArray pro_signature) { + jbyteArray rotating_key) { return run_catching_cxx_exception_or_throws(env, [=] { return util::bytes_from_vector( env, - session::encrypt_for_community_inbox( + session::encode_for_community_inbox( JavaByteArrayRef(env, plaintext).get(), JavaByteArrayRef(env, my_ed25519_priv_key).get(), std::chrono::milliseconds { timestamp_ms }, *java_to_cpp_array<33>(env, recipient_pub_key), *java_to_cpp_array<32>(env, community_server_pub_key), - java_to_cpp_array<64>(env, pro_signature) + rotating_key ? JavaByteArrayRef(env, rotating_key).get() : std::span() )); }); } @@ -168,7 +168,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encryptFor jlong timestamp_ms, jbyteArray group_ed25519_public_key, jbyteArray group_ed25519_private_key, - jbyteArray pro_signature) { + jbyteArray rotating_key) { return run_catching_cxx_exception_or_throws(env, [=] { session::cleared_uc32 group_private_key; @@ -177,13 +177,13 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encryptFor return util::bytes_from_vector( env, - session::encrypt_for_group( + session::encode_for_group( JavaByteArrayRef(env, plaintext).get(), JavaByteArrayRef(env, my_ed25519_priv_key).get(), std::chrono::milliseconds { timestamp_ms }, *java_to_cpp_array<33>(env, group_ed25519_public_key), group_private_key, - java_to_cpp_array<64>(env, pro_signature) + rotating_key ? JavaByteArrayRef(env, rotating_key).get() : std::span() )); }); } \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt index 8de9a48..a190186 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt @@ -8,7 +8,7 @@ object SessionProtocol : LibSessionUtilCApi() { myEd25519PrivKey: ByteArray, timestampMs: Long, recipientPubKey: ByteArray, // 33 bytes prefixed key - proSignature: ByteArray?, // 64 bytes + proRotatingEd25519PrivKey: ByteArray?, // 64 bytes ): ByteArray external fun encryptForCommunityInbox( @@ -17,7 +17,7 @@ object SessionProtocol : LibSessionUtilCApi() { timestampMs: Long, recipientPubKey: ByteArray, // 33 bytes prefixed key communityServerPubKey: ByteArray, // 32 bytes key - proSignature: ByteArray?, // 64 bytes + proRotatingEd25519PrivKey: ByteArray?, // 64 bytes ): ByteArray external fun encryptForGroup( @@ -26,7 +26,7 @@ object SessionProtocol : LibSessionUtilCApi() { timestampMs: Long, groupEd25519PublicKey: ByteArray, // 33 bytes 03 prefixed key groupEd25519PrivateKey: ByteArray, // 32 bytes group "encryption" key - proSignature: ByteArray?, // 64 bytes + proRotatingEd25519PrivKey: ByteArray?, // 64 bytes ): ByteArray external fun decryptEnvelope( diff --git a/libsession-util b/libsession-util index db2e063..a02c38c 160000 --- a/libsession-util +++ b/libsession-util @@ -1 +1 @@ -Subproject commit db2e063cd73715433a0466c6219671b2c460addf +Subproject commit a02c38c5d43180525b5a10697e1a2d1bb3141dbd From 2d1c0ffaf6fc7519dc9e6e8638343583c3ba126f Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Thu, 2 Oct 2025 22:11:48 +0800 Subject: [PATCH 05/16] Update to latest libsession --- libsession-util | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsession-util b/libsession-util index a02c38c..2d82cd7 160000 --- a/libsession-util +++ b/libsession-util @@ -1 +1 @@ -Subproject commit a02c38c5d43180525b5a10697e1a2d1bb3141dbd +Subproject commit 2d82cd72eec3a9760a07de93fc5e1c3699e8eedd From f046fed74d52808334ecdb7be5b04abae1176c49 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Mon, 6 Oct 2025 11:46:32 +0800 Subject: [PATCH 06/16] Update to latest libsession-util --- libsession-util | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsession-util b/libsession-util index 2d82cd7..c4ec3d1 160000 --- a/libsession-util +++ b/libsession-util @@ -1 +1 @@ -Subproject commit 2d82cd72eec3a9760a07de93fc5e1c3699e8eedd +Subproject commit c4ec3d18522964827782d23dcaa91af671944025 From b9a021406f5cdd21f8ddaa203dd16532c1c55f5c Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Tue, 28 Oct 2025 14:50:09 +1100 Subject: [PATCH 07/16] Fix compilation issue --- library/src/main/cpp/protocol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/cpp/protocol.cpp b/library/src/main/cpp/protocol.cpp index eeccce2..bbcf780 100644 --- a/library/src/main/cpp/protocol.cpp +++ b/library/src/main/cpp/protocol.cpp @@ -89,7 +89,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decryptEnv } } - key.ed25519_privkeys = { privateKeysStorage.data(), privateKeysStorage.size() }; + key.decrypt_keys = { privateKeysStorage.data(), privateKeysStorage.size() }; return run_catching_cxx_exception_or_throws(env, [&] { auto envelop = session::decode_envelope(key, JavaByteArrayRef(env, java_payload).get(), From 80f501d60f0e11e4474389b5c800e8c066726eaf Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Mon, 3 Nov 2025 13:28:46 +1100 Subject: [PATCH 08/16] Updated libsession-util --- libsession-util | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsession-util b/libsession-util index 5fd7882..0d6f9ec 160000 --- a/libsession-util +++ b/libsession-util @@ -1 +1 @@ -Subproject commit 5fd78825b79dbc9dbabd06cd64ae37e845d95904 +Subproject commit 0d6f9ec06cd1678059897d07b9d7f151a8c6171a From 6b1dd3d5cd565cc0700ccb64795050325c9229f5 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Mon, 3 Nov 2025 14:18:46 +1100 Subject: [PATCH 09/16] Updating message encoding/decoding APIs --- library/src/main/cpp/protocol.cpp | 90 ++++++++++++------- .../protocol/DecodedCommunityMessage.kt | 18 ++++ ...DecryptedEnvelope.kt => DecodedEnvelop.kt} | 2 +- .../libsession_util/protocol/ProStatus.kt | 4 +- .../protocol/SessionProtocol.kt | 18 ++-- 5 files changed, 93 insertions(+), 39 deletions(-) create mode 100644 library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedCommunityMessage.kt rename library/src/main/java/network/loki/messenger/libsession_util/protocol/{DecryptedEnvelope.kt => DecodedEnvelop.kt} (96%) diff --git a/library/src/main/cpp/protocol.cpp b/library/src/main/cpp/protocol.cpp index bbcf780..07d5c2b 100644 --- a/library/src/main/cpp/protocol.cpp +++ b/library/src/main/cpp/protocol.cpp @@ -8,8 +8,8 @@ using namespace jni_utils; -static JavaLocalRef serializeProStatus(JNIEnv *env, const session::DecodedEnvelope & envelope) { - if (!envelope.pro.has_value()) { +static JavaLocalRef serializeProStatus(JNIEnv *env, const std::optional & pro) { + if (!pro.has_value()) { JavaLocalRef noneClass(env, env->FindClass("network/loki/messenger/libsession_util/protocol/ProStatus$None")); auto fieldId = env->GetStaticFieldID( noneClass.get(), @@ -17,12 +17,12 @@ static JavaLocalRef serializeProStatus(JNIEnv *env, const session::Deco return {env, env->GetStaticObjectField(noneClass.get(), fieldId)}; } - if (envelope.pro->status == session::ProStatus::Valid) { + if (pro->status == session::ProStatus::Valid) { JavaLocalRef validClass(env, env->FindClass("network/loki/messenger/libsession_util/protocol/ProStatus$Valid")); auto init = env->GetMethodID(validClass.get(), "", "(JJ)V"); return {env, env->NewObject(validClass.get(), init, - static_cast(envelope.pro->proof.expiry_unix_ts.time_since_epoch().count()), - static_cast(envelope.pro->features))}; + static_cast(pro->proof.expiry_unix_ts.time_since_epoch().count()), + static_cast(pro->features))}; } JavaLocalRef invalidClass(env, env->FindClass("network/loki/messenger/libsession_util/protocol/ProStatus$Invalid")); @@ -34,12 +34,12 @@ static JavaLocalRef serializeProStatus(JNIEnv *env, const session::Deco extern "C" JNIEXPORT jobject JNICALL -Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decryptEnvelope(JNIEnv *env, - jobject thiz, - jobject java_key, - jbyteArray java_payload, - jlong now_epoch_seconds, - jbyteArray java_pro_backend_pub_key) { +Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeEnvelope(JNIEnv *env, + jobject thiz, + jobject java_key, + jbyteArray java_payload, + jlong now_epoch_mills, + jbyteArray java_pro_backend_pub_key) { session::DecodeEnvelopeKey key; @@ -93,14 +93,14 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decryptEnv return run_catching_cxx_exception_or_throws(env, [&] { auto envelop = session::decode_envelope(key, JavaByteArrayRef(env, java_payload).get(), - std::chrono::sys_seconds { std::chrono::seconds { now_epoch_seconds } }, + std::chrono::sys_time { std::chrono::milliseconds { now_epoch_mills } }, *java_to_cpp_array<32>(env, java_pro_backend_pub_key)); JavaLocalRef sender_ed25519(env, util::bytes_from_span(env, envelop.sender_ed25519_pubkey)); JavaLocalRef sender_x25519(env, util::bytes_from_span(env, envelop.sender_x25519_pubkey)); JavaLocalRef content(env, util::bytes_from_vector(env, envelop.content_plaintext)); - JavaLocalRef envelopClass(env, env->FindClass("network/loki/messenger/libsession_util/protocol/DecryptedEnvelope")); + JavaLocalRef envelopClass(env, env->FindClass("network/loki/messenger/libsession_util/protocol/DecodedEnvelop")); jmethodID init = env->GetMethodID( envelopClass.get(), "", @@ -108,7 +108,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decryptEnv ); return env->NewObject(envelopClass.get(), init, - serializeProStatus(env, envelop).get(), + serializeProStatus(env, envelop.pro).get(), content.get(), sender_ed25519.get(), sender_x25519.get(), @@ -119,13 +119,13 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decryptEnv extern "C" JNIEXPORT jbyteArray JNICALL -Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encryptFor1o1(JNIEnv *env, - jobject thiz, - jbyteArray plaintext, - jbyteArray my_ed25519_priv_key, - jlong timestamp_ms, - jbyteArray recipient_pub_key, - jbyteArray rotating_key) { +Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeFor1o1(JNIEnv *env, + jobject thiz, + jbyteArray plaintext, + jbyteArray my_ed25519_priv_key, + jlong timestamp_ms, + jbyteArray recipient_pub_key, + jbyteArray rotating_key) { return run_catching_cxx_exception_or_throws(env, [=] { return util::bytes_from_vector( env, @@ -141,7 +141,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encryptFor extern "C" JNIEXPORT jbyteArray JNICALL -Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encryptForCommunityInbox( +Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeForCommunityInbox( JNIEnv *env, jobject thiz, jbyteArray plaintext, jbyteArray my_ed25519_priv_key, jlong timestamp_ms, jbyteArray recipient_pub_key, jbyteArray community_server_pub_key, jbyteArray rotating_key) { @@ -161,14 +161,14 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encryptFor extern "C" JNIEXPORT jbyteArray JNICALL -Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encryptForGroup(JNIEnv *env, - jobject thiz, - jbyteArray plaintext, - jbyteArray my_ed25519_priv_key, - jlong timestamp_ms, - jbyteArray group_ed25519_public_key, - jbyteArray group_ed25519_private_key, - jbyteArray rotating_key) { +Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeForGroup(JNIEnv *env, + jobject thiz, + jbyteArray plaintext, + jbyteArray my_ed25519_priv_key, + jlong timestamp_ms, + jbyteArray group_ed25519_public_key, + jbyteArray group_ed25519_private_key, + jbyteArray rotating_key) { return run_catching_cxx_exception_or_throws(env, [=] { session::cleared_uc32 group_private_key; @@ -186,4 +186,34 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encryptFor rotating_key ? JavaByteArrayRef(env, rotating_key).get() : std::span() )); }); +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeForCommunity( + JNIEnv *env, jobject thiz, jbyteArray payload, jlong now_epoch_ms, + jbyteArray pro_backend_pub_key) { + return run_catching_cxx_exception_or_throws(env, [=] { + jni_utils::JavaByteArrayRef payload_ref(env, payload); + + auto decoded = session::decode_for_community( + payload_ref.get(), + std::chrono::sys_time { std::chrono::milliseconds { now_epoch_ms } }, + *java_to_cpp_array<32>(env, pro_backend_pub_key) + ); + + JavaLocalRef envelopClass(env, env->FindClass("network/loki/messenger/libsession_util/protocol/DecodedCommunityMessage")); + jmethodID init = env->GetMethodID( + envelopClass.get(), + "", + "(Lnetwork/loki/messenger/libsession_util/protocol/ProStatus;[B)V" + ); + + return env->NewObject( + envelopClass.get(), + init, + serializeProStatus(env, decoded.pro).get(), + util::bytes_from_vector(env, decoded.content_plaintext) + ); + }); } \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedCommunityMessage.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedCommunityMessage.kt new file mode 100644 index 0000000..7f8c703 --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedCommunityMessage.kt @@ -0,0 +1,18 @@ +package network.loki.messenger.libsession_util.protocol + +import androidx.annotation.Keep +import network.loki.messenger.libsession_util.util.Bytes + +data class DecodedCommunityMessage( + val proStatus: ProStatus, + val contentPlainText: Bytes, +) { + @Keep + constructor( + proStatus: ProStatus, + contentPlainText: ByteArray, + ): this( + proStatus = proStatus, + contentPlainText = Bytes(contentPlainText), + ) +} diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecryptedEnvelope.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelop.kt similarity index 96% rename from library/src/main/java/network/loki/messenger/libsession_util/protocol/DecryptedEnvelope.kt rename to library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelop.kt index 26ef94b..413a575 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecryptedEnvelope.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelop.kt @@ -4,7 +4,7 @@ import androidx.annotation.Keep import network.loki.messenger.libsession_util.util.Bytes import java.time.Instant -data class DecryptedEnvelope( +data class DecodedEnvelop( val proStatus: ProStatus, val contentPlainText: Bytes, val senderEd25519PubKey: Bytes, diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProStatus.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProStatus.kt index 01b220e..49b6a94 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProStatus.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProStatus.kt @@ -14,10 +14,10 @@ sealed interface ProStatus { ) { @Keep constructor( - expiresAtEpochSeconds: Long, + expiresAtEpochMills: Long, proFeatures: Long ): this( - expiresAt = Instant.ofEpochSecond(expiresAtEpochSeconds), + expiresAt = Instant.ofEpochMilli(expiresAtEpochMills), proFeatures = proFeatures.toFeatures() ) } diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt index a190186..444773b 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt @@ -3,7 +3,7 @@ package network.loki.messenger.libsession_util.protocol import network.loki.messenger.libsession_util.LibSessionUtilCApi object SessionProtocol : LibSessionUtilCApi() { - external fun encryptFor1o1( + external fun encodeFor1o1( plaintext: ByteArray, myEd25519PrivKey: ByteArray, timestampMs: Long, @@ -11,7 +11,7 @@ object SessionProtocol : LibSessionUtilCApi() { proRotatingEd25519PrivKey: ByteArray?, // 64 bytes ): ByteArray - external fun encryptForCommunityInbox( + external fun encodeForCommunityInbox( plaintext: ByteArray, myEd25519PrivKey: ByteArray, timestampMs: Long, @@ -20,7 +20,7 @@ object SessionProtocol : LibSessionUtilCApi() { proRotatingEd25519PrivKey: ByteArray?, // 64 bytes ): ByteArray - external fun encryptForGroup( + external fun encodeForGroup( plaintext: ByteArray, myEd25519PrivKey: ByteArray, timestampMs: Long, @@ -29,10 +29,16 @@ object SessionProtocol : LibSessionUtilCApi() { proRotatingEd25519PrivKey: ByteArray?, // 64 bytes ): ByteArray - external fun decryptEnvelope( + external fun decodeEnvelope( key: DecryptEnvelopeKey, payload: ByteArray, - nowEpochSeconds: Long, + nowEpochMs: Long, proBackendPubKey: ByteArray, // 32 bytes backend key - ): DecryptedEnvelope + ): DecodedEnvelop + + external fun decodeForCommunity( + payload: ByteArray, + nowEpochMs: Long, + proBackendPubKey: ByteArray, // 32 bytes backend key + ): DecodedCommunityMessage } \ No newline at end of file From cf52cff5d61b77cb71eff3a13c0be2ae1bf4f365 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Mon, 3 Nov 2025 16:58:19 +1100 Subject: [PATCH 10/16] Integrating WIP --- library/src/main/cpp/protocol.cpp | 44 ++++++++++++++++--- .../protocol/SessionProtocol.kt | 12 +++++ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/library/src/main/cpp/protocol.cpp b/library/src/main/cpp/protocol.cpp index 07d5c2b..24efa51 100644 --- a/library/src/main/cpp/protocol.cpp +++ b/library/src/main/cpp/protocol.cpp @@ -134,8 +134,9 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeFor1 JavaByteArrayRef(env, my_ed25519_priv_key).get(), std::chrono::milliseconds { timestamp_ms }, *java_to_cpp_array<33>(env, recipient_pub_key), - rotating_key ? JavaByteArrayRef(env, rotating_key).get() : std::span() - )); + rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) : std::nullopt + ) + ); }); } @@ -154,8 +155,9 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeForC std::chrono::milliseconds { timestamp_ms }, *java_to_cpp_array<33>(env, recipient_pub_key), *java_to_cpp_array<32>(env, community_server_pub_key), - rotating_key ? JavaByteArrayRef(env, rotating_key).get() : std::span() - )); + rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) : std::nullopt + ) + ); }); } @@ -183,8 +185,9 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeForG std::chrono::milliseconds { timestamp_ms }, *java_to_cpp_array<33>(env, group_ed25519_public_key), group_private_key, - rotating_key ? JavaByteArrayRef(env, rotating_key).get() : std::span() - )); + rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) : std::nullopt + ) + ); }); } @@ -216,4 +219,33 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeForC util::bytes_from_vector(env, decoded.content_plaintext) ); }); +} + +extern "C" +JNIEXPORT jbyteArray JNICALL +Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeForCommunity( + JNIEnv *env, + jobject thiz, + jbyteArray plaintext, + jbyteArray rotating_key) { + return run_catching_cxx_exception_or_throws(env, [=] { + return util::bytes_from_vector( + env, + session::encode_for_community( + JavaByteArrayRef(env, plaintext).get(), + rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) : std::nullopt + ) + ); + }); +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeFor1o1(JNIEnv *env, + jobject thiz, + jobject key, + jbyteArray payload, + jlong now_epoch_ms, + jbyteArray pro_backend_pub_key) { + // TODO: implement decodeFor1o1() } \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt index 444773b..8f05054 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt @@ -11,6 +11,13 @@ object SessionProtocol : LibSessionUtilCApi() { proRotatingEd25519PrivKey: ByteArray?, // 64 bytes ): ByteArray + external fun decodeFor1o1( + myEd25519PrivKey: ByteArray, + payload: ByteArray, + nowEpochMs: Long, + proBackendPubKey: ByteArray, // 32 bytes backend key + ): DecodedEnvelop + external fun encodeForCommunityInbox( plaintext: ByteArray, myEd25519PrivKey: ByteArray, @@ -20,6 +27,11 @@ object SessionProtocol : LibSessionUtilCApi() { proRotatingEd25519PrivKey: ByteArray?, // 64 bytes ): ByteArray + external fun encodeForCommunity( + plaintext: ByteArray, + proRotatingEd25519PrivKey: ByteArray?, // 64 bytes + ): ByteArray + external fun encodeForGroup( plaintext: ByteArray, myEd25519PrivKey: ByteArray, From 290907f688ad98cb72dbe87031cb441d9ecad91d Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Wed, 5 Nov 2025 15:22:32 +1100 Subject: [PATCH 11/16] Different decode API for different type of messages --- library/src/main/cpp/protocol.cpp | 173 +++++++++--------- .../protocol/DecodedEnvelop.kt | 3 + .../protocol/DecryptEnvelopeKey.kt | 22 --- .../libsession_util/protocol/Envelop.kt | 25 +++ .../protocol/SessionProtocol.kt | 18 +- 5 files changed, 128 insertions(+), 113 deletions(-) delete mode 100644 library/src/main/java/network/loki/messenger/libsession_util/protocol/DecryptEnvelopeKey.kt create mode 100644 library/src/main/java/network/loki/messenger/libsession_util/protocol/Envelop.kt diff --git a/library/src/main/cpp/protocol.cpp b/library/src/main/cpp/protocol.cpp index 24efa51..960ad31 100644 --- a/library/src/main/cpp/protocol.cpp +++ b/library/src/main/cpp/protocol.cpp @@ -32,91 +32,48 @@ static JavaLocalRef serializeProStatus(JNIEnv *env, const std::optional return {env, env->GetStaticObjectField(invalidClass.get(), fieldId)}; } -extern "C" -JNIEXPORT jobject JNICALL -Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeEnvelope(JNIEnv *env, - jobject thiz, - jobject java_key, - jbyteArray java_payload, - jlong now_epoch_mills, - jbyteArray java_pro_backend_pub_key) { - - session::DecodeEnvelopeKey key; - - std::vector> privateKeysStorage; - - struct RegularStorage { - JavaLocalRef ed25519PrivKeyRef; - JavaByteArrayRef ed25519PrivKeyBytesRef; - }; - - struct GroupData { - JavaLocalRef groupPubKeyRef; - JavaByteArrayRef groupPubKeyBytesRef; - - std::vector, JavaByteArrayRef>> groupKeysRef; - }; - - std::optional regularStorage; - std::optional groupStorage; - - JavaLocalRef regularClazz(env, env->FindClass("network/loki/messenger/libsession_util/protocol/DecryptEnvelopeKey$Regular")); - if (env->IsInstanceOf(java_key, regularClazz.get())) { - auto bytes = reinterpret_cast(env->CallObjectMethod(java_key, env->GetMethodID(regularClazz.get(), "getEd25519PrivKey", "()[B"))); - regularStorage.emplace(RegularStorage { - .ed25519PrivKeyRef = JavaLocalRef(env, bytes), - .ed25519PrivKeyBytesRef = JavaByteArrayRef(env, bytes) - }); - - privateKeysStorage.push_back(regularStorage->ed25519PrivKeyBytesRef.get()); - } - - JavaLocalRef groupClazz(env, env->FindClass("network/loki/messenger/libsession_util/protocol/DecryptEnvelopeKey$Group")); - if (env->IsInstanceOf(java_key, groupClazz.get())) { - auto pubKeyBytes = reinterpret_cast(env->CallObjectMethod(java_key, env->GetMethodID(groupClazz.get(), "getGroupEd25519PubKey", "()[B"))); - groupStorage.emplace(GroupData { - .groupPubKeyRef = JavaLocalRef(env, pubKeyBytes), - .groupPubKeyBytesRef = JavaByteArrayRef(env, pubKeyBytes) - }); - - key.group_ed25519_pubkey.emplace(groupStorage->groupPubKeyBytesRef.get()); - - JavaLocalRef privKeyArrays(env, reinterpret_cast(env->CallObjectMethod(java_key, env->GetMethodID(groupClazz.get(), "getGroupKeys", "()[[B")))); - for (int i = 0, size = env->GetArrayLength(privKeyArrays.get()); i < size; i++) { - auto bytes = reinterpret_cast(env->GetObjectArrayElement(privKeyArrays.get(), i)); - const auto &last = groupStorage->groupKeysRef.emplace_back(JavaLocalRef(env, bytes), JavaByteArrayRef(env, bytes)); - privateKeysStorage.emplace_back(last.second.get()); - } - } - - key.decrypt_keys = { privateKeysStorage.data(), privateKeysStorage.size() }; - - return run_catching_cxx_exception_or_throws(env, [&] { - auto envelop = session::decode_envelope(key, JavaByteArrayRef(env, java_payload).get(), - std::chrono::sys_time { std::chrono::milliseconds { now_epoch_mills } }, - *java_to_cpp_array<32>(env, java_pro_backend_pub_key)); - - JavaLocalRef sender_ed25519(env, util::bytes_from_span(env, envelop.sender_ed25519_pubkey)); - JavaLocalRef sender_x25519(env, util::bytes_from_span(env, envelop.sender_x25519_pubkey)); - JavaLocalRef content(env, util::bytes_from_vector(env, envelop.content_plaintext)); +static JavaLocalRef serializeEnvelop(JNIEnv *env, const session::Envelope &envelope) { + JavaLocalRef envelopClass(env, env->FindClass("network/loki/messenger/libsession_util/protocol/Envelope")); + jmethodID init = env->GetMethodID( + envelopClass.get(), + "", + "([BJ[B)V" + ); + + return {env, env->NewObject(envelopClass.get(), + init, + static_cast(envelope.timestamp.count()), + (envelope.flags & SESSION_PROTOCOL_ENVELOPE_FLAGS_SOURCE) + ? util::bytes_from_span(env, envelope.source) + : nullptr, + (envelope.flags & SESSION_PROTOCOL_ENVELOPE_FLAGS_SERVER_TIMESTAMP) + ? static_cast(envelope.server_timestamp) + : 0, + util::bytes_from_span(env, envelope.pro_sig))}; +} - JavaLocalRef envelopClass(env, env->FindClass("network/loki/messenger/libsession_util/protocol/DecodedEnvelop")); - jmethodID init = env->GetMethodID( - envelopClass.get(), - "", - "(Lnetwork/loki/messenger/libsession_util/protocol/ProStatus;[B[B[BJ)V" - ); +static jobject serializeDecodedEnvelope(JNIEnv *env, const session::DecodedEnvelope &envelop) { + JavaLocalRef sender_ed25519(env, util::bytes_from_span(env, envelop.sender_ed25519_pubkey)); + JavaLocalRef sender_x25519(env, util::bytes_from_span(env, envelop.sender_x25519_pubkey)); + JavaLocalRef content(env, util::bytes_from_vector(env, envelop.content_plaintext)); + + JavaLocalRef envelopClass(env, env->FindClass("network/loki/messenger/libsession_util/protocol/DecodedEnvelop")); + jmethodID init = env->GetMethodID( + envelopClass.get(), + "", + "(Lnetwork/loki/messenger/libsession_util/protocol/Envelope;Lnetwork/loki/messenger/libsession_util/protocol/ProStatus;[B[B[BJ)V" + ); + + return env->NewObject(envelopClass.get(), init, + serializeEnvelop(env, envelop.envelope).get(), + serializeProStatus(env, envelop.pro).get(), + content.get(), + sender_ed25519.get(), + sender_x25519.get(), + static_cast(envelop.envelope.timestamp.count())); - return env->NewObject(envelopClass.get(), init, - serializeProStatus(env, envelop.pro).get(), - content.get(), - sender_ed25519.get(), - sender_x25519.get(), - static_cast(envelop.envelope.timestamp.count())); - }); } - extern "C" JNIEXPORT jbyteArray JNICALL Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeFor1o1(JNIEnv *env, @@ -243,9 +200,59 @@ extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeFor1o1(JNIEnv *env, jobject thiz, - jobject key, + jbyteArray key, jbyteArray payload, jlong now_epoch_ms, jbyteArray pro_backend_pub_key) { - // TODO: implement decodeFor1o1() + return run_catching_cxx_exception_or_throws(env, [=] { + JavaByteArrayRef key_ref(env, key); + + std::array, 1> keys = { key_ref.get() }; + + session::DecodeEnvelopeKey decode_key { + .decrypt_keys = std::span(keys.data(), keys.size()), + }; + + return serializeDecodedEnvelope(env, session::decode_envelope( + decode_key, + JavaByteArrayRef(env, payload).get(), + std::chrono::sys_time { std::chrono::milliseconds { now_epoch_ms } }, + *java_to_cpp_array<32>(env, pro_backend_pub_key) + )); + }); +} + + +extern "C" +JNIEXPORT jobject JNICALL +Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeForGroup(JNIEnv *env, + jobject thiz, + jbyteArray payload, + jbyteArray my_ed25519_priv_key, + jlong now_epoch_ms, + jbyteArray group_ed25519_public_key, + jobjectArray group_ed25519_private_keys, + jbyteArray pro_backend_pub_key) { + return run_catching_cxx_exception_or_throws(env, [=] { + std::vector private_keys_refs; + std::vector> private_keys_spans; + for (int i = 0, size = env->GetArrayLength(group_ed25519_private_keys); i < size; i++) { + auto bytes = reinterpret_cast(env->GetObjectArrayElement(group_ed25519_private_keys, i)); + private_keys_spans.emplace_back(private_keys_refs.emplace_back(env, bytes).get()); + } + + JavaByteArrayRef group_pub_key_ref(env, group_ed25519_public_key); + + session::DecodeEnvelopeKey decode_key { + .group_ed25519_pubkey = std::make_optional(group_pub_key_ref.get()), + .decrypt_keys = std::span(private_keys_spans.data(), private_keys_spans.size()), + }; + + return serializeDecodedEnvelope(env, session::decode_envelope( + decode_key, + JavaByteArrayRef(env, payload).get(), + std::chrono::sys_time { std::chrono::milliseconds { now_epoch_ms } }, + *java_to_cpp_array<32>(env, pro_backend_pub_key) + )); + }); } \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelop.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelop.kt index 413a575..9d6923b 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelop.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelop.kt @@ -5,6 +5,7 @@ import network.loki.messenger.libsession_util.util.Bytes import java.time.Instant data class DecodedEnvelop( + val envelop: Envelop, val proStatus: ProStatus, val contentPlainText: Bytes, val senderEd25519PubKey: Bytes, @@ -13,12 +14,14 @@ data class DecodedEnvelop( ) { @Keep constructor( + envelop: Envelop, proStatus: ProStatus, contentPlainText: ByteArray, senderEd25519PubKey: ByteArray, senderX25519PubKey: ByteArray, timestampEpochMills: Long ): this( + envelop = envelop, proStatus = proStatus, contentPlainText = Bytes(contentPlainText), senderEd25519PubKey = Bytes(senderEd25519PubKey), diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecryptEnvelopeKey.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecryptEnvelopeKey.kt deleted file mode 100644 index 58de8fd..0000000 --- a/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecryptEnvelopeKey.kt +++ /dev/null @@ -1,22 +0,0 @@ -package network.loki.messenger.libsession_util.protocol - - -sealed interface DecryptEnvelopeKey { - - class Group( - val groupEd25519PubKey: ByteArray, - val groupKeys: Array - ) : DecryptEnvelopeKey { - constructor( - groupEd25519PubKey: ByteArray, - groupKeys: Collection - ) : this( - groupEd25519PubKey, - groupKeys.toTypedArray() - ) - } - - class Regular( - val ed25519PrivKey: ByteArray - ) : DecryptEnvelopeKey -} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/Envelop.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/Envelop.kt new file mode 100644 index 0000000..d522cc5 --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/Envelop.kt @@ -0,0 +1,25 @@ +package network.loki.messenger.libsession_util.protocol + +import androidx.annotation.Keep +import network.loki.messenger.libsession_util.util.Bytes +import java.time.Instant + +data class Envelop( + val timestamp: Instant, + val source: Bytes?, // 33 bytes prefixed public key + val serverTimestamp: Instant?, + val proSignature: Bytes, // 64 bytes +) { + @Keep + constructor( + timestampMs: Long, + source: ByteArray?, + serverTimestampMs: Long, + proSignature: ByteArray + ): this( + timestamp = Instant.ofEpochMilli(timestampMs), + source = source?.let { Bytes(it) }, + serverTimestamp = if (serverTimestampMs != 0L) Instant.ofEpochMilli(serverTimestampMs) else null, + proSignature = Bytes(proSignature) + ) +} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt index 8f05054..82cae40 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt @@ -32,6 +32,12 @@ object SessionProtocol : LibSessionUtilCApi() { proRotatingEd25519PrivKey: ByteArray?, // 64 bytes ): ByteArray + external fun decodeForCommunity( + payload: ByteArray, + nowEpochMs: Long, + proBackendPubKey: ByteArray, // 32 bytes backend key + ): DecodedCommunityMessage + external fun encodeForGroup( plaintext: ByteArray, myEd25519PrivKey: ByteArray, @@ -41,16 +47,12 @@ object SessionProtocol : LibSessionUtilCApi() { proRotatingEd25519PrivKey: ByteArray?, // 64 bytes ): ByteArray - external fun decodeEnvelope( - key: DecryptEnvelopeKey, + external fun decodeForGroup( payload: ByteArray, + myEd25519PrivKey: ByteArray, nowEpochMs: Long, + groupEd25519PublicKey: ByteArray, // 33 bytes 03 prefixed key + groupEd25519PrivateKeys: Array, // all available group private keys proBackendPubKey: ByteArray, // 32 bytes backend key ): DecodedEnvelop - - external fun decodeForCommunity( - payload: ByteArray, - nowEpochMs: Long, - proBackendPubKey: ByteArray, // 32 bytes backend key - ): DecodedCommunityMessage } \ No newline at end of file From ecf3339b8eefaed141a14cb4c55c2046fb758d61 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Thu, 6 Nov 2025 09:47:35 +1100 Subject: [PATCH 12/16] Posting version on PR --- .github/workflows/check.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 9ff400b..0007c4f 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -12,6 +12,7 @@ jobs: permissions: contents: read packages: write + pull-requests: write steps: - uses: actions/checkout@v4 @@ -26,3 +27,23 @@ jobs: - name: Verify build for PR run: ./gradlew check + + + post_version: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + - name: Extract version + id: extract_version + run: | + VERSION=$(git describe --tags --dirty) + echo "version=$VERSION" >> $GITHUB_OUTPUT + - name: Posting comment about the build + uses: marocchino/sticky-pull-request-comment@v2 + with: + header: version + message: | + The build version for this PR will be: `${{ steps.extract_version.outputs.version }}` + From 0d3d9a17625f4af1aa53ae1728864b2f4eb7470c Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Thu, 6 Nov 2025 09:49:44 +1100 Subject: [PATCH 13/16] Posting version --- .github/workflows/check.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 0007c4f..8c26367 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -15,26 +15,27 @@ jobs: pull-requests: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: - submodules: 'recursive' + submodules: "recursive" - name: Set up JDK 17 uses: actions/setup-java@v4 with: - java-version: '17' - distribution: 'temurin' + java-version: "17" + distribution: "temurin" cache: gradle - name: Verify build for PR run: ./gradlew check - post_version: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: - submodules: 'recursive' + fetch-tags: true + fetch-depth: 0 + - name: Extract version id: extract_version run: | @@ -46,4 +47,3 @@ jobs: header: version message: | The build version for this PR will be: `${{ steps.extract_version.outputs.version }}` - From 1278e66a6bb493ca661d731971bc4be20e8fadb7 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Thu, 6 Nov 2025 09:50:57 +1100 Subject: [PATCH 14/16] Concurrency limit --- .github/workflows/check.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 8c26367..292fb48 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -6,6 +6,11 @@ on: - opened - synchronize +# Limit to one concurrent run per PR +concurrency: + group: "check-pr-${{ github.event.pull_request.number }}" + cancel-in-progress: true + jobs: build: runs-on: ubuntu-latest From 4fb53ede5d4e66542664e9a8404e27fe5851a475 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Thu, 6 Nov 2025 14:54:44 +1100 Subject: [PATCH 15/16] Fix crashes --- library/src/main/cpp/protocol.cpp | 4 ++-- .../protocol/{DecodedEnvelop.kt => DecodedEnvelope.kt} | 8 ++++---- .../libsession_util/protocol/{Envelop.kt => Envelope.kt} | 2 +- .../messenger/libsession_util/protocol/SessionProtocol.kt | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) rename library/src/main/java/network/loki/messenger/libsession_util/protocol/{DecodedEnvelop.kt => DecodedEnvelope.kt} (87%) rename library/src/main/java/network/loki/messenger/libsession_util/protocol/{Envelop.kt => Envelope.kt} (97%) diff --git a/library/src/main/cpp/protocol.cpp b/library/src/main/cpp/protocol.cpp index 960ad31..653e54a 100644 --- a/library/src/main/cpp/protocol.cpp +++ b/library/src/main/cpp/protocol.cpp @@ -37,7 +37,7 @@ static JavaLocalRef serializeEnvelop(JNIEnv *env, const session::Envelo jmethodID init = env->GetMethodID( envelopClass.get(), "", - "([BJ[B)V" + "(J[BJ[B)V" ); return {env, env->NewObject(envelopClass.get(), @@ -57,7 +57,7 @@ static jobject serializeDecodedEnvelope(JNIEnv *env, const session::DecodedEnvel JavaLocalRef sender_x25519(env, util::bytes_from_span(env, envelop.sender_x25519_pubkey)); JavaLocalRef content(env, util::bytes_from_vector(env, envelop.content_plaintext)); - JavaLocalRef envelopClass(env, env->FindClass("network/loki/messenger/libsession_util/protocol/DecodedEnvelop")); + JavaLocalRef envelopClass(env, env->FindClass("network/loki/messenger/libsession_util/protocol/DecodedEnvelope")); jmethodID init = env->GetMethodID( envelopClass.get(), "", diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelop.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelope.kt similarity index 87% rename from library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelop.kt rename to library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelope.kt index 9d6923b..35e1f4d 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelop.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelope.kt @@ -4,8 +4,8 @@ import androidx.annotation.Keep import network.loki.messenger.libsession_util.util.Bytes import java.time.Instant -data class DecodedEnvelop( - val envelop: Envelop, +data class DecodedEnvelope( + val envelope: Envelope, val proStatus: ProStatus, val contentPlainText: Bytes, val senderEd25519PubKey: Bytes, @@ -14,14 +14,14 @@ data class DecodedEnvelop( ) { @Keep constructor( - envelop: Envelop, + envelope: Envelope, proStatus: ProStatus, contentPlainText: ByteArray, senderEd25519PubKey: ByteArray, senderX25519PubKey: ByteArray, timestampEpochMills: Long ): this( - envelop = envelop, + envelope = envelope, proStatus = proStatus, contentPlainText = Bytes(contentPlainText), senderEd25519PubKey = Bytes(senderEd25519PubKey), diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/Envelop.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/Envelope.kt similarity index 97% rename from library/src/main/java/network/loki/messenger/libsession_util/protocol/Envelop.kt rename to library/src/main/java/network/loki/messenger/libsession_util/protocol/Envelope.kt index d522cc5..2711d51 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/protocol/Envelop.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/Envelope.kt @@ -4,7 +4,7 @@ import androidx.annotation.Keep import network.loki.messenger.libsession_util.util.Bytes import java.time.Instant -data class Envelop( +data class Envelope( val timestamp: Instant, val source: Bytes?, // 33 bytes prefixed public key val serverTimestamp: Instant?, diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt index 82cae40..3d18b85 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt @@ -16,7 +16,7 @@ object SessionProtocol : LibSessionUtilCApi() { payload: ByteArray, nowEpochMs: Long, proBackendPubKey: ByteArray, // 32 bytes backend key - ): DecodedEnvelop + ): DecodedEnvelope external fun encodeForCommunityInbox( plaintext: ByteArray, @@ -54,5 +54,5 @@ object SessionProtocol : LibSessionUtilCApi() { groupEd25519PublicKey: ByteArray, // 33 bytes 03 prefixed key groupEd25519PrivateKeys: Array, // all available group private keys proBackendPubKey: ByteArray, // 32 bytes backend key - ): DecodedEnvelop + ): DecodedEnvelope } \ No newline at end of file From c15b19c1d8f9fcd3d532aad19cdd53397e6b854e Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Fri, 7 Nov 2025 14:39:59 +1100 Subject: [PATCH 16/16] Update to latest libsession-util --- libsession-util | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsession-util b/libsession-util index 0d6f9ec..6134c47 160000 --- a/libsession-util +++ b/libsession-util @@ -1 +1 @@ -Subproject commit 0d6f9ec06cd1678059897d07b9d7f151a8c6171a +Subproject commit 6134c4718ae094be53deeb2b4285bed475b20b88