From c6926a837ce544e7f13834544bba5a66856487fc Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Mon, 10 Nov 2025 16:59:29 +1100 Subject: [PATCH 01/26] Add addProPayment/getProProof integration --- library/src/main/cpp/CMakeLists.txt | 2 + library/src/main/cpp/jni_utils.h | 4 + library/src/main/cpp/pro_backend.cpp | 84 +++++++++++++++++++ library/src/main/cpp/pro_proof.cpp | 54 ++++++++++++ .../libsession_util/pro/AddProPayment.kt | 81 ++++++++++++++++++ .../libsession_util/pro/GetProProof.kt | 34 ++++++++ .../libsession_util/pro/PaymentProvider.kt | 6 ++ .../messenger/libsession_util/pro/ProProof.kt | 40 +++++++++ .../libsession_util/pro/ProProofResponse.kt | 24 ++++++ .../libsession_util/pro/ResponseStatus.kt | 5 ++ 10 files changed, 334 insertions(+) create mode 100644 library/src/main/cpp/pro_backend.cpp create mode 100644 library/src/main/cpp/pro_proof.cpp create mode 100644 library/src/main/java/network/loki/messenger/libsession_util/pro/AddProPayment.kt create mode 100644 library/src/main/java/network/loki/messenger/libsession_util/pro/GetProProof.kt create mode 100644 library/src/main/java/network/loki/messenger/libsession_util/pro/PaymentProvider.kt create mode 100644 library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt create mode 100644 library/src/main/java/network/loki/messenger/libsession_util/pro/ProProofResponse.kt create mode 100644 library/src/main/java/network/loki/messenger/libsession_util/pro/ResponseStatus.kt diff --git a/library/src/main/cpp/CMakeLists.txt b/library/src/main/cpp/CMakeLists.txt index f475972..386fe94 100644 --- a/library/src/main/cpp/CMakeLists.txt +++ b/library/src/main/cpp/CMakeLists.txt @@ -95,6 +95,8 @@ set(SOURCES attachments.cpp webp_utils.cpp gif_utils.cpp + pro_backend.cpp + pro_proof.cpp ${cgif_SOURCE_DIR}/src/cgif.c ${cgif_SOURCE_DIR}/src/cgif_rgb.c diff --git a/library/src/main/cpp/jni_utils.h b/library/src/main/cpp/jni_utils.h index c74b6b4..8365597 100644 --- a/library/src/main/cpp/jni_utils.h +++ b/library/src/main/cpp/jni_utils.h @@ -194,6 +194,10 @@ namespace jni_utils { std::span get() const { return data; } + + std::span get_raw() const { + return std::span(reinterpret_cast(data.data()), data.size()); + } }; /** diff --git a/library/src/main/cpp/pro_backend.cpp b/library/src/main/cpp/pro_backend.cpp new file mode 100644 index 0000000..d381a37 --- /dev/null +++ b/library/src/main/cpp/pro_backend.cpp @@ -0,0 +1,84 @@ +#include +#include "jni_utils.h" +#include "util.h" + +#include + +using namespace jni_utils; + +extern "C" +JNIEXPORT jstring JNICALL +Java_network_loki_messenger_libsession_1util_pro_AddProPaymentRequests_buildJson(JNIEnv *env, + jobject thiz, + jint version, + jbyteArray master_private_key, + jbyteArray rotating_private_key, + jint payment_provider, + jstring payment_transaction_id, + jstring payment_order_id) { + return run_catching_cxx_exception_or_throws(env, [=]() { + return util::jstringFromOptional(env, session::pro_backend::AddProPaymentRequest::build_to_json( + version, + JavaByteArrayRef(env, master_private_key).get(), + JavaByteArrayRef(env, rotating_private_key).get(), + static_cast(payment_provider), + JavaStringRef(env, payment_transaction_id).get_raw(), + JavaStringRef(env, payment_order_id).get_raw() + ) + ); + }); +} + + +extern "C" +JNIEXPORT jobject JNICALL +Java_network_loki_messenger_libsession_1util_pro_ProProofResponse_00024Companion_nativeParseRaw( + JNIEnv *env, jobject thiz, jstring json) { + return run_catching_cxx_exception_or_throws(env, [=]() { + auto response = session::pro_backend::AddProPaymentOrGetProProofResponse::parse( + JavaStringRef(env, json).view() + ); + + if (response.errors.empty()) { + JavaLocalRef pro_proof_class(env, env->FindClass("network/loki/messenger/libsession_util/pro/ProProof")); + JavaLocalRef success_class(env, env->FindClass("network/loki/messenger/libsession_util/pro/ProProofResponse$Success")); + + return env->NewObject( + success_class.get(), + env->GetMethodID(success_class.get(), "", "(Lnetwork/loki/messenger/libsession_util/pro/ProProof;)V"), + env->NewObject( + pro_proof_class.get(), + env->GetMethodID(pro_proof_class.get(), "", "(J)V"), + reinterpret_cast(new session::ProProof(response.proof)) + ) + ); + } + + JavaLocalRef error_class(env, env->FindClass("network/loki/messenger/libsession_util/pro/ProProofResponse$Failure")); + + return env->NewObject( + error_class.get(), + env->GetMethodID(error_class.get(), "", "(ILjava/util/List;)V"), + static_cast(response.status), + jstring_list_from_collection(env, response.errors) + ); + }); +} + +extern "C" +JNIEXPORT jstring JNICALL +Java_network_loki_messenger_libsession_1util_pro_GetProProofRequests_buildJson(JNIEnv *env, + jint version, + jobject thiz, + jbyteArray master_private_key, + jbyteArray rotating_private_key, + jlong now_unix_ts) { + return run_catching_cxx_exception_or_throws(env, [=] () { + return util::jstringFromOptional(env, session::pro_backend::GetProProofRequest::build_to_json( + version, + JavaByteArrayRef(env, master_private_key).get(), + JavaByteArrayRef(env, rotating_private_key).get(), + std::chrono::sys_time { std::chrono::milliseconds{static_cast(now_unix_ts)} } + )); + }); +} \ No newline at end of file diff --git a/library/src/main/cpp/pro_proof.cpp b/library/src/main/cpp/pro_proof.cpp new file mode 100644 index 0000000..f78c5d9 --- /dev/null +++ b/library/src/main/cpp/pro_proof.cpp @@ -0,0 +1,54 @@ +#include + +#include +#include "util.h" + + +extern "C" +JNIEXPORT jint JNICALL +Java_network_loki_messenger_libsession_1util_pro_ProProof_00024Companion_nativeGetVersion( + JNIEnv *env, jobject thiz, jlong native_value) { + return static_cast( + reinterpret_cast(native_value)->version); +} + + +extern "C" +JNIEXPORT jlong JNICALL +Java_network_loki_messenger_libsession_1util_pro_ProProof_00024Companion_nativeGetExpiry( + JNIEnv *env, jobject thiz, jlong native_value) { + return static_cast( + reinterpret_cast(native_value)->expiry_unix_ts.time_since_epoch().count()); +} + +extern "C" +JNIEXPORT jbyteArray JNICALL +Java_network_loki_messenger_libsession_1util_pro_ProProof_00024Companion_nativeGetRotatingPubKey( + JNIEnv *env, jobject thiz, jlong native_value) { + const auto& rotating_pubkey = + reinterpret_cast(native_value)->rotating_pubkey; + + return util::bytes_from_span(env, rotating_pubkey); +} + +extern "C" +JNIEXPORT jstring JNICALL +Java_network_loki_messenger_libsession_1util_pro_ProProof_00024Companion_nativeSerialize( + JNIEnv *env, jobject thiz, jlong native_value) { + // TODO: implement nativeSerialize() +} + +extern "C" +JNIEXPORT jlong JNICALL +Java_network_loki_messenger_libsession_1util_pro_ProProof_00024Companion_nativeDeserialize( + JNIEnv *env, jobject thiz, jstring data) { + // TODO: implement nativeDeserialize() +} + +extern "C" +JNIEXPORT void JNICALL +Java_network_loki_messenger_libsession_1util_pro_ProProof_00024Companion_nativeDestroy(JNIEnv *env, + jobject thiz, + jlong native_value) { + delete reinterpret_cast(native_value); +} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/AddProPayment.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/AddProPayment.kt new file mode 100644 index 0000000..b33eb2b --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/pro/AddProPayment.kt @@ -0,0 +1,81 @@ +package network.loki.messenger.libsession_util.pro + +import network.loki.messenger.libsession_util.LibSessionUtilCApi + +object AddProPaymentRequests : LibSessionUtilCApi() { + private external fun buildJson( + version: Int, + masterPrivateKey: ByteArray, + rotatingPrivateKey: ByteArray, + paymentProvider: Int, + paymentTransactionId: String, + paymentOrderId: String, + ): String + + fun buildJson( + /** + * Version of the request to build a hash for + */ + version: Int, + /** + * 64-byte libsodium style or 32 byte Ed25519 master private key + */ + masterPrivateKey: ByteArray, + + /** + * 64-byte libsodium style or 32 byte Ed25519 rotating private key + */ + rotatingPrivateKey: ByteArray, + + /** + * Provider that the payment to register is coming from + */ + paymentProvider: PaymentProvider, + + /** + * ID that is associated with the payment from the payment provider + */ + paymentTransactionId: String, + + /** + * Order ID that is associated with the payment + */ + paymentOrderId: String, + + ): String = buildJson( + version = version, + masterPrivateKey = masterPrivateKey, + rotatingPrivateKey = rotatingPrivateKey, + paymentProvider = paymentProvider.nativeValue, + paymentTransactionId = paymentTransactionId, + paymentOrderId = paymentOrderId, + ) +} + + +enum class AddProPaymentError(internal val nativeValue: Int) { + Generic(1), + AlreadyRedeemed(2), + UnknownPayment(3), +} + + + +object AddProPaymentResponses { + fun parse(jsonResponse: String): ProProofResponse { + return when (val r = ProProofResponse.parseRaw(jsonResponse)) { + is ProProofResponse.Failure -> { + ProProofResponse.Failure( + status = AddProPaymentError.entries.firstOrNull { + it.nativeValue == r.status + } ?: AddProPaymentError.Generic, + errors = r.errors, + ) + } + + is ProProofResponse.Success -> { + ProProofResponse.Success(r.proof) + } + } + } +} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/GetProProof.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/GetProProof.kt new file mode 100644 index 0000000..e34e660 --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/pro/GetProProof.kt @@ -0,0 +1,34 @@ +package network.loki.messenger.libsession_util.pro + +import network.loki.messenger.libsession_util.LibSessionUtilCApi + +enum class GetProProofError { + Generic, +} + +object GetProProofRequests : LibSessionUtilCApi() { + external fun buildJson( + version: Int, + /** + * 64-byte libsodium style or 32 byte Ed25519 master private key + */ + masterPrivateKey: ByteArray, + + /** + * 64-byte libsodium style or 32 byte Ed25519 rotating private key + */ + rotatingPrivateKey: ByteArray, + nowUnixTs: Long, + ): String +} + +object GetProProofResponses { + fun parse(json: String): ProProofResponse { + return when (val r = ProProofResponse.parseRaw(json)) { + is ProProofResponse.Success -> ProProofResponse.Success(r.proof) + is ProProofResponse.Failure -> { + ProProofResponse.Failure(GetProProofError.Generic, r.errors) + } + } + } +} diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/PaymentProvider.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/PaymentProvider.kt new file mode 100644 index 0000000..cf21f39 --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/pro/PaymentProvider.kt @@ -0,0 +1,6 @@ +package network.loki.messenger.libsession_util.pro + +enum class PaymentProvider(val nativeValue: Int) { + GooglePlayStore(1), + AppleAppStore(2), +} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt new file mode 100644 index 0000000..0d6e3ec --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt @@ -0,0 +1,40 @@ +package network.loki.messenger.libsession_util.pro + +import androidx.annotation.Keep +import network.loki.messenger.libsession_util.LibSessionUtilCApi +import java.time.Instant + +class ProProof @Keep private constructor(private val nativeValue: Long) { + + val version: Int get() = nativeGetVersion(nativeValue) + val expiry: Instant get() = Instant.ofEpochSecond(nativeGetExpiry(nativeValue)) + val rotatingPubKey: ByteArray get() = nativeGetRotatingPubKey(nativeValue) + + + /** + * Serialize the [ProProof] to a byte array for storage or transmission + */ + fun serialize(): String = nativeSerialize(nativeValue) + + + protected fun finalize() { + nativeDestroy(nativeValue) + } + + + companion object : LibSessionUtilCApi() { + private external fun nativeGetVersion(nativeValue: Long): Int + private external fun nativeGetExpiry(nativeValue: Long): Long + private external fun nativeGetRotatingPubKey(nativeValue: Long): ByteArray + private external fun nativeSerialize(nativeValue: Long): String + private external fun nativeDeserialize(data: String): Long + private external fun nativeDestroy(nativeValue: Long) + + /** + * Deserialize a [ProProof] from a byte array + */ + fun deserialize(data: String): ProProof { + return ProProof(nativeDeserialize(data)) + } + } +} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProofResponse.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProofResponse.kt new file mode 100644 index 0000000..e32596a --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProofResponse.kt @@ -0,0 +1,24 @@ +package network.loki.messenger.libsession_util.pro + +import androidx.annotation.Keep +import network.loki.messenger.libsession_util.LibSessionUtilCApi + + +/** + * Represents the response that returns a [ProProof] + */ +sealed interface ProProofResponse { + data class Success @Keep constructor(val proof: ProProof) : ProProofResponse + data class Failure(val status: T, val errors: List) : ProProofResponse + + companion object : LibSessionUtilCApi() { + /** + * Parses a raw JSON string into a [ProProofResponse] with an integer status code. + */ + private external fun nativeParseRaw(json: String): ProProofResponse + + internal fun parseRaw(json: String): ProProofResponse { + return nativeParseRaw(json) + } + } +} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/ResponseStatus.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/ResponseStatus.kt new file mode 100644 index 0000000..559e642 --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/pro/ResponseStatus.kt @@ -0,0 +1,5 @@ +package network.loki.messenger.libsession_util.pro + +typealias ResponseStatus = Int + +const val RESPONSE_STATUS_SUCCESS: ResponseStatus = 200 \ No newline at end of file From b93e7cc85c2d1589cf28f2f0032e14f381013ced Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Tue, 11 Nov 2025 10:22:22 +1100 Subject: [PATCH 02/26] Added master key generation and pro proof serialization --- library/src/main/cpp/CMakeLists.txt | 2 + library/src/main/cpp/ed25519.cpp | 15 +++++++ library/src/main/cpp/pro_proof.cpp | 39 +++++++++++++++++-- .../loki/messenger/libsession_util/ED25519.kt | 9 +++++ 4 files changed, 62 insertions(+), 3 deletions(-) diff --git a/library/src/main/cpp/CMakeLists.txt b/library/src/main/cpp/CMakeLists.txt index 386fe94..ea96a21 100644 --- a/library/src/main/cpp/CMakeLists.txt +++ b/library/src/main/cpp/CMakeLists.txt @@ -160,4 +160,6 @@ target_link_libraries( # Specifies the target library. webpdemux webpdecoder yuv + nlohmann_json + oxenc ) \ No newline at end of file diff --git a/library/src/main/cpp/ed25519.cpp b/library/src/main/cpp/ed25519.cpp index cd0d51b..62c315e 100644 --- a/library/src/main/cpp/ed25519.cpp +++ b/library/src/main/cpp/ed25519.cpp @@ -43,4 +43,19 @@ Java_network_loki_messenger_libsession_1util_ED25519_generate(JNIEnv *env, jobje return jni_utils::new_key_pair(env, util::bytes_from_span(env, pk), util::bytes_from_span(env, sk)); }); +} + +extern "C" +JNIEXPORT jbyteArray JNICALL +Java_network_loki_messenger_libsession_1util_ED25519_generateProKeyPair(JNIEnv *env, jobject thiz, + jbyteArray ed25519_seed) { + return jni_utils::run_catching_cxx_exception_or_throws(env, [=] { + return util::bytes_from_span( + env, + session::ed25519::ed25519_pro_privkey_for_ed25519_seed( + jni_utils::JavaByteArrayRef(env, ed25519_seed).get() + ) + ); + + }); } \ No newline at end of file diff --git a/library/src/main/cpp/pro_proof.cpp b/library/src/main/cpp/pro_proof.cpp index f78c5d9..52605ca 100644 --- a/library/src/main/cpp/pro_proof.cpp +++ b/library/src/main/cpp/pro_proof.cpp @@ -1,7 +1,10 @@ #include - +#include +#include #include + #include "util.h" +#include "jni_utils.h" extern "C" @@ -35,14 +38,44 @@ extern "C" JNIEXPORT jstring JNICALL Java_network_loki_messenger_libsession_1util_pro_ProProof_00024Companion_nativeSerialize( JNIEnv *env, jobject thiz, jlong native_value) { - // TODO: implement nativeSerialize() + const auto& proof = + *reinterpret_cast(native_value); + nlohmann::json j; + j["version"] = proof.version; + j["gen_index_hash"] = oxenc::to_base64(proof.gen_index_hash); + j["rotating_pubkey"] = oxenc::to_base64(proof.rotating_pubkey); + j["expiry_unix_ts_ms"] = proof.expiry_unix_ts.time_since_epoch().count(); + j["sig"] = oxenc::to_base64(proof.sig); + + return util::jstringFromOptional(env, j.dump()); +} + +template +void from_json(const nlohmann::json& j, std::array& arr) { + auto b64_str = j.get(); + auto bytes = oxenc::from_base64(b64_str); + if (bytes.size() != N) { + throw std::invalid_argument{"Invalid array size in from_json"}; + } + std::copy(bytes.begin(), bytes.end(), arr.begin()); } extern "C" JNIEXPORT jlong JNICALL Java_network_loki_messenger_libsession_1util_pro_ProProof_00024Companion_nativeDeserialize( JNIEnv *env, jobject thiz, jstring data) { - // TODO: implement nativeDeserialize() + return jni_utils::run_catching_cxx_exception_or_throws(env, [=]() { + auto j = nlohmann::json::parse(jni_utils::JavaStringRef(env, data).view()); + + return reinterpret_cast(new session::ProProof { + .version = j.at("version").get(), + .gen_index_hash = j.at("gen_index_hash").get(), + .rotating_pubkey = j.at("rotating_pubkey").get(), + .expiry_unix_ts = std::chrono::sys_time{ + std::chrono::milliseconds{static_cast(j.at("expiry_unix_ts_ms").get())}}, + .sig = j.at("sig").get(), + }); + }); } extern "C" diff --git a/library/src/main/java/network/loki/messenger/libsession_util/ED25519.kt b/library/src/main/java/network/loki/messenger/libsession_util/ED25519.kt index 392e9a7..a9aff66 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/ED25519.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/ED25519.kt @@ -29,4 +29,13 @@ object ED25519 : LibSessionUtilCApi() { ): Boolean external fun generate(seed: ByteArray?): KeyPair + + /** + * Generate the deterministic Master Session Pro key for signing requests to interact with the + * Session Pro features of the protocol. + * + * @param ed25519Seed The seed the user uses to generate their session id + * @return The libsodium-style Master Session Pro Ed25519 secret key, 64 bytes. + */ + external fun generateProPrivateKey(ed25519Seed: ByteArray): ByteArray } \ No newline at end of file From 13d217a56873e122cb01c7b7ab2d445eee2e5be8 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Wed, 12 Nov 2025 12:16:35 +1100 Subject: [PATCH 03/26] Only integrate singing of the requests --- library/src/main/cpp/jni_utils.h | 9 +- library/src/main/cpp/pro_backend.cpp | 115 +++++++++-------- library/src/main/cpp/pro_proof.cpp | 118 ++++++++---------- library/src/main/cpp/protocol.cpp | 103 +++++++-------- .../libsession_util/pro/AddProPayment.kt | 81 ------------ .../libsession_util/pro/BackendRequests.kt | 39 ++++++ .../libsession_util/pro/GetProProof.kt | 34 ----- .../libsession_util/pro/PaymentProvider.kt | 6 - .../messenger/libsession_util/pro/ProProof.kt | 79 ++++++++---- .../libsession_util/pro/ProProofResponse.kt | 24 ---- .../libsession_util/pro/ResponseStatus.kt | 5 - .../protocol/DecodedCommunityMessage.kt | 17 ++- .../protocol/DecodedEnvelope.kt | 17 ++- .../libsession_util/protocol/ProStatus.kt | 24 ---- 14 files changed, 286 insertions(+), 385 deletions(-) delete mode 100644 library/src/main/java/network/loki/messenger/libsession_util/pro/AddProPayment.kt create mode 100644 library/src/main/java/network/loki/messenger/libsession_util/pro/BackendRequests.kt delete mode 100644 library/src/main/java/network/loki/messenger/libsession_util/pro/GetProProof.kt delete mode 100644 library/src/main/java/network/loki/messenger/libsession_util/pro/PaymentProvider.kt delete mode 100644 library/src/main/java/network/loki/messenger/libsession_util/pro/ProProofResponse.kt delete mode 100644 library/src/main/java/network/loki/messenger/libsession_util/pro/ResponseStatus.kt delete mode 100644 library/src/main/java/network/loki/messenger/libsession_util/protocol/ProStatus.kt diff --git a/library/src/main/cpp/jni_utils.h b/library/src/main/cpp/jni_utils.h index 8365597..87399ff 100644 --- a/library/src/main/cpp/jni_utils.h +++ b/library/src/main/cpp/jni_utils.h @@ -210,8 +210,13 @@ namespace jni_utils { public: JavaByteArrayRef(JNIEnv *env, jbyteArray byte_array) : env(env), byte_array(byte_array) { - jsize length = env->GetArrayLength(byte_array); - data = std::span(reinterpret_cast(env->GetByteArrayElements(byte_array, nullptr)), length); + if (byte_array) { + jsize length = env->GetArrayLength(byte_array); + data = std::span( + reinterpret_cast(env->GetByteArrayElements(byte_array, + nullptr)), + length); + } } JavaByteArrayRef(const JavaByteArrayRef &) = delete; diff --git a/library/src/main/cpp/pro_backend.cpp b/library/src/main/cpp/pro_backend.cpp index d381a37..1f1e0c8 100644 --- a/library/src/main/cpp/pro_backend.cpp +++ b/library/src/main/cpp/pro_backend.cpp @@ -6,79 +6,76 @@ using namespace jni_utils; +static jobject serializeMasterRotatingSignatures( + JNIEnv *env, const session::pro_backend::MasterRotatingSignatures &sigs) { + JavaLocalRef result_class( + env, + env->FindClass( + "network/loki/messenger/libsession_util/pro/BackendRequests$MasterRotatingSignatures")); + + return env->NewObject( + result_class.get(), + env->GetMethodID(result_class.get(), "", "([B[B)V"), + util::bytes_from_span(env, sigs.master_sig), + util::bytes_from_span(env, sigs.rotating_sig) + ); +} + extern "C" -JNIEXPORT jstring JNICALL -Java_network_loki_messenger_libsession_1util_pro_AddProPaymentRequests_buildJson(JNIEnv *env, - jobject thiz, - jint version, - jbyteArray master_private_key, - jbyteArray rotating_private_key, - jint payment_provider, - jstring payment_transaction_id, - jstring payment_order_id) { - return run_catching_cxx_exception_or_throws(env, [=]() { - return util::jstringFromOptional(env, session::pro_backend::AddProPaymentRequest::build_to_json( - version, +JNIEXPORT jobject JNICALL +Java_network_loki_messenger_libsession_1util_pro_BackendRequests_signAddProPaymentRequest( + JNIEnv *env, jobject thiz, jint version, jbyteArray master_private_key, + jbyteArray rotating_private_key, jint payment_provider, jstring payment_id, + jstring order_id) { + return run_catching_cxx_exception_or_throws(env, [=] { + auto sigs = session::pro_backend::AddProPaymentRequest::build_sigs( + static_cast(version), JavaByteArrayRef(env, master_private_key).get(), JavaByteArrayRef(env, rotating_private_key).get(), - static_cast(payment_provider), - JavaStringRef(env, payment_transaction_id).get_raw(), - JavaStringRef(env, payment_order_id).get_raw() - ) - ); + static_cast( + payment_provider), + JavaStringRef(env, payment_id).get_raw(), + JavaStringRef(env, order_id).get_raw()); + + return serializeMasterRotatingSignatures(env, sigs); }); } - extern "C" JNIEXPORT jobject JNICALL -Java_network_loki_messenger_libsession_1util_pro_ProProofResponse_00024Companion_nativeParseRaw( - JNIEnv *env, jobject thiz, jstring json) { - return run_catching_cxx_exception_or_throws(env, [=]() { - auto response = session::pro_backend::AddProPaymentOrGetProProofResponse::parse( - JavaStringRef(env, json).view() +Java_network_loki_messenger_libsession_1util_pro_BackendRequests_signGetProProofRequest(JNIEnv *env, + jobject thiz, + jint version, + jbyteArray master_private_key, + jbyteArray rotating_private_key, + jlong unix_ts_ms) { + return run_catching_cxx_exception_or_throws(env, [=] { + auto sigs = session::pro_backend::GetProProofRequest::build_sigs( + version, + JavaByteArrayRef(env, master_private_key).get(), + JavaByteArrayRef(env, rotating_private_key).get(), + std::chrono::sys_time{ + std::chrono::milliseconds{unix_ts_ms}} ); - if (response.errors.empty()) { - JavaLocalRef pro_proof_class(env, env->FindClass("network/loki/messenger/libsession_util/pro/ProProof")); - JavaLocalRef success_class(env, env->FindClass("network/loki/messenger/libsession_util/pro/ProProofResponse$Success")); - - return env->NewObject( - success_class.get(), - env->GetMethodID(success_class.get(), "", "(Lnetwork/loki/messenger/libsession_util/pro/ProProof;)V"), - env->NewObject( - pro_proof_class.get(), - env->GetMethodID(pro_proof_class.get(), "", "(J)V"), - reinterpret_cast(new session::ProProof(response.proof)) - ) - ); - } - - JavaLocalRef error_class(env, env->FindClass("network/loki/messenger/libsession_util/pro/ProProofResponse$Failure")); - - return env->NewObject( - error_class.get(), - env->GetMethodID(error_class.get(), "", "(ILjava/util/List;)V"), - static_cast(response.status), - jstring_list_from_collection(env, response.errors) - ); + return serializeMasterRotatingSignatures(env, sigs); }); } extern "C" -JNIEXPORT jstring JNICALL -Java_network_loki_messenger_libsession_1util_pro_GetProProofRequests_buildJson(JNIEnv *env, - jint version, - jobject thiz, - jbyteArray master_private_key, - jbyteArray rotating_private_key, - jlong now_unix_ts) { - return run_catching_cxx_exception_or_throws(env, [=] () { - return util::jstringFromOptional(env, session::pro_backend::GetProProofRequest::build_to_json( - version, +JNIEXPORT jbyteArray JNICALL +Java_network_loki_messenger_libsession_1util_pro_BackendRequests_signGetProStatusRequest( + JNIEnv *env, jobject thiz, jint version, jbyteArray master_private_key, jlong now_ms, + jint count) { + return run_catching_cxx_exception_or_throws(env, [=] { + auto sig = session::pro_backend::GetProStatusRequest::build_sig( + static_cast(version), JavaByteArrayRef(env, master_private_key).get(), - JavaByteArrayRef(env, rotating_private_key).get(), - std::chrono::sys_time { std::chrono::milliseconds{static_cast(now_unix_ts)} } - )); + std::chrono::sys_time{ + std::chrono::milliseconds{now_ms}}, + static_cast(count) + ); + + return util::bytes_from_span(env, sig); }); } \ No newline at end of file diff --git a/library/src/main/cpp/pro_proof.cpp b/library/src/main/cpp/pro_proof.cpp index 52605ca..5b4142c 100644 --- a/library/src/main/cpp/pro_proof.cpp +++ b/library/src/main/cpp/pro_proof.cpp @@ -6,82 +6,62 @@ #include "util.h" #include "jni_utils.h" +using namespace jni_utils; extern "C" JNIEXPORT jint JNICALL -Java_network_loki_messenger_libsession_1util_pro_ProProof_00024Companion_nativeGetVersion( - JNIEnv *env, jobject thiz, jlong native_value) { - return static_cast( - reinterpret_cast(native_value)->version); -} +Java_network_loki_messenger_libsession_1util_pro_ProProof_status(JNIEnv *env, jobject thiz, + jbyteArray verify_pub_key, + jlong now_unix_ts, + jbyteArray signed_message_data, + jbyteArray signed_message_signature) { + return run_catching_cxx_exception_or_throws(env, [=]() { + JavaLocalRef clazz(env, env->GetObjectClass(thiz)); + auto get_version_method = env->GetMethodID(clazz.get(), "getVersion", "()I"); + auto get_gen_index_hash_method = env->GetMethodID(clazz.get(), "getGenIndexHash", "()[B"); + auto get_rotating_pub_key_method = env->GetMethodID(clazz.get(), "getRotatingPubKey", + "()[B"); + auto get_expiry_method = env->GetMethodID(clazz.get(), "getExpiryMs", "()J"); + auto get_signature_method = env->GetMethodID(clazz.get(), "getSignature", "()[B"); + auto version = env->CallIntMethod(thiz, get_version_method); + JavaLocalRef gen_index_hash_bytes_obj(env, + static_cast(env->CallObjectMethod( + thiz, + get_gen_index_hash_method))); + JavaLocalRef rotating_pub_key_bytes_obj(env, + static_cast(env->CallObjectMethod( + thiz, + get_rotating_pub_key_method))); + auto expiry_ms = env->CallLongMethod(thiz, get_expiry_method); + JavaLocalRef signature_bytes_obj(env, + static_cast(env->CallObjectMethod( + thiz, get_signature_method))); -extern "C" -JNIEXPORT jlong JNICALL -Java_network_loki_messenger_libsession_1util_pro_ProProof_00024Companion_nativeGetExpiry( - JNIEnv *env, jobject thiz, jlong native_value) { - return static_cast( - reinterpret_cast(native_value)->expiry_unix_ts.time_since_epoch().count()); -} - -extern "C" -JNIEXPORT jbyteArray JNICALL -Java_network_loki_messenger_libsession_1util_pro_ProProof_00024Companion_nativeGetRotatingPubKey( - JNIEnv *env, jobject thiz, jlong native_value) { - const auto& rotating_pubkey = - reinterpret_cast(native_value)->rotating_pubkey; - - return util::bytes_from_span(env, rotating_pubkey); -} - -extern "C" -JNIEXPORT jstring JNICALL -Java_network_loki_messenger_libsession_1util_pro_ProProof_00024Companion_nativeSerialize( - JNIEnv *env, jobject thiz, jlong native_value) { - const auto& proof = - *reinterpret_cast(native_value); - nlohmann::json j; - j["version"] = proof.version; - j["gen_index_hash"] = oxenc::to_base64(proof.gen_index_hash); - j["rotating_pubkey"] = oxenc::to_base64(proof.rotating_pubkey); - j["expiry_unix_ts_ms"] = proof.expiry_unix_ts.time_since_epoch().count(); - j["sig"] = oxenc::to_base64(proof.sig); - - return util::jstringFromOptional(env, j.dump()); -} + std::optional signed_msg; + JavaByteArrayRef signed_message_data_ref(env, signed_message_data); + JavaByteArrayRef signed_message_signature_ref(env, signed_message_signature); -template -void from_json(const nlohmann::json& j, std::array& arr) { - auto b64_str = j.get(); - auto bytes = oxenc::from_base64(b64_str); - if (bytes.size() != N) { - throw std::invalid_argument{"Invalid array size in from_json"}; - } - std::copy(bytes.begin(), bytes.end(), arr.begin()); -} + if (signed_message_data && signed_message_signature) { + signed_msg.emplace(session::ProSignedMessage { + .sig = signed_message_signature_ref.get(), + .msg = signed_message_data_ref.get(), + }); + } -extern "C" -JNIEXPORT jlong JNICALL -Java_network_loki_messenger_libsession_1util_pro_ProProof_00024Companion_nativeDeserialize( - JNIEnv *env, jobject thiz, jstring data) { - return jni_utils::run_catching_cxx_exception_or_throws(env, [=]() { - auto j = nlohmann::json::parse(jni_utils::JavaStringRef(env, data).view()); + session::ProProof pro_proof { + .version = static_cast(version), + .gen_index_hash = *java_to_cpp_array<32>(env, gen_index_hash_bytes_obj.get()), + .rotating_pubkey = *java_to_cpp_array<32>(env, rotating_pub_key_bytes_obj.get()), + .expiry_unix_ts = std::chrono::sys_time( + std::chrono::milliseconds(expiry_ms)), + .sig = *java_to_cpp_array<64>(env, signature_bytes_obj.get()), + }; - return reinterpret_cast(new session::ProProof { - .version = j.at("version").get(), - .gen_index_hash = j.at("gen_index_hash").get(), - .rotating_pubkey = j.at("rotating_pubkey").get(), - .expiry_unix_ts = std::chrono::sys_time{ - std::chrono::milliseconds{static_cast(j.at("expiry_unix_ts_ms").get())}}, - .sig = j.at("sig").get(), - }); + return static_cast(pro_proof.status( + JavaByteArrayRef(env, verify_pub_key).get(), + std::chrono::sys_time{std::chrono::milliseconds(now_unix_ts)}, + signed_msg + )); }); -} - -extern "C" -JNIEXPORT void JNICALL -Java_network_loki_messenger_libsession_1util_pro_ProProof_00024Companion_nativeDestroy(JNIEnv *env, - jobject thiz, - jlong native_value) { - delete reinterpret_cast(native_value); } \ No newline at end of file diff --git a/library/src/main/cpp/protocol.cpp b/library/src/main/cpp/protocol.cpp index 653e54a..02493e5 100644 --- a/library/src/main/cpp/protocol.cpp +++ b/library/src/main/cpp/protocol.cpp @@ -7,33 +7,24 @@ using namespace jni_utils; - -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(), - "INSTANCE", "Lnetwork/loki/messenger/libsession_util/protocol/ProStatus$None;"); - return {env, env->GetStaticObjectField(noneClass.get(), fieldId)}; - } - - 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(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")); - auto fieldId = env->GetStaticFieldID( - invalidClass.get(), - "INSTANCE", "Lnetwork/loki/messenger/libsession_util/protocol/ProStatus$Invalid;"); - return {env, env->GetStaticObjectField(invalidClass.get(), fieldId)}; +static JavaLocalRef serializeProProof(JNIEnv *env, const session::ProProof &proof) { + JavaLocalRef pro_proof_clazz(env, env->FindClass( + "network/loki/messenger/libsession_util/pro/ProProof")); + jmethodID init = env->GetMethodID(pro_proof_clazz.get(), "", "(I[B[BJ[B)V"); + return {env, env->NewObject( + pro_proof_clazz.get(), + init, + static_cast(proof.version), + util::bytes_from_span(env, proof.gen_index_hash), + util::bytes_from_span(env, proof.rotating_pubkey), + static_cast(proof.expiry_unix_ts.time_since_epoch().count()), + util::bytes_from_span(env, proof.sig) + )}; } static JavaLocalRef serializeEnvelop(JNIEnv *env, const session::Envelope &envelope) { - JavaLocalRef envelopClass(env, env->FindClass("network/loki/messenger/libsession_util/protocol/Envelope")); + JavaLocalRef envelopClass(env, env->FindClass( + "network/loki/messenger/libsession_util/protocol/Envelope")); jmethodID init = env->GetMethodID( envelopClass.get(), "", @@ -44,11 +35,11 @@ static JavaLocalRef serializeEnvelop(JNIEnv *env, const session::Envelo init, static_cast(envelope.timestamp.count()), (envelope.flags & SESSION_PROTOCOL_ENVELOPE_FLAGS_SOURCE) - ? util::bytes_from_span(env, envelope.source) - : nullptr, + ? util::bytes_from_span(env, envelope.source) + : nullptr, (envelope.flags & SESSION_PROTOCOL_ENVELOPE_FLAGS_SERVER_TIMESTAMP) - ? static_cast(envelope.server_timestamp) - : 0, + ? static_cast(envelope.server_timestamp) + : 0, util::bytes_from_span(env, envelope.pro_sig))}; } @@ -57,16 +48,19 @@ 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/DecodedEnvelope")); + JavaLocalRef envelopClass(env, env->FindClass( + "network/loki/messenger/libsession_util/protocol/DecodedEnvelope")); jmethodID init = env->GetMethodID( envelopClass.get(), "", - "(Lnetwork/loki/messenger/libsession_util/protocol/Envelope;Lnetwork/loki/messenger/libsession_util/protocol/ProStatus;[B[B[BJ)V" + "(Lnetwork/loki/messenger/libsession_util/protocol/Envelope;Lnetwork/loki/messenger/libsession_util/pro/ProProof$Status;Lnetwork/loki/messenger/libsession_util/pro/ProProof;[B[B[BJ)V" ); return env->NewObject(envelopClass.get(), init, serializeEnvelop(env, envelop.envelope).get(), - serializeProStatus(env, envelop.pro).get(), + envelop.pro ? static_cast(envelop.pro->status) + : static_cast(-1), + envelop.pro ? serializeProProof(env, envelop.pro->proof).get() : nullptr, content.get(), sender_ed25519.get(), sender_x25519.get(), @@ -89,9 +83,10 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeFor1 session::encode_for_1o1( JavaByteArrayRef(env, plaintext).get(), JavaByteArrayRef(env, my_ed25519_priv_key).get(), - std::chrono::milliseconds { timestamp_ms }, + std::chrono::milliseconds{timestamp_ms}, *java_to_cpp_array<33>(env, recipient_pub_key), - rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) : std::nullopt + rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) + : std::nullopt ) ); }); @@ -109,10 +104,11 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeForC session::encode_for_community_inbox( JavaByteArrayRef(env, plaintext).get(), JavaByteArrayRef(env, my_ed25519_priv_key).get(), - std::chrono::milliseconds { timestamp_ms }, + 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 ? std::optional(JavaByteArrayRef(env, rotating_key).get()) : std::nullopt + rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) + : std::nullopt ) ); }); @@ -139,10 +135,11 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeForG session::encode_for_group( JavaByteArrayRef(env, plaintext).get(), JavaByteArrayRef(env, my_ed25519_priv_key).get(), - std::chrono::milliseconds { timestamp_ms }, + std::chrono::milliseconds{timestamp_ms}, *java_to_cpp_array<33>(env, group_ed25519_public_key), group_private_key, - rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) : std::nullopt + rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) + : std::nullopt ) ); }); @@ -158,21 +155,25 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeForC auto decoded = session::decode_for_community( payload_ref.get(), - std::chrono::sys_time { std::chrono::milliseconds { now_epoch_ms } }, + 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")); + 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" + "(Lnetwork/loki/messenger/libsession_util/protocol/pro/ProProof$Status;Lnetwork/loki/messenger/libsession_util/protocol/pro/ProProof;[B)V" ); return env->NewObject( envelopClass.get(), init, - serializeProStatus(env, decoded.pro).get(), + decoded.pro ? static_cast(decoded.pro->status) + : static_cast(-1), + decoded.pro ? serializeProProof(env, decoded.pro->proof).get() : nullptr, util::bytes_from_vector(env, decoded.content_plaintext) ); }); @@ -190,7 +191,8 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeForC env, session::encode_for_community( JavaByteArrayRef(env, plaintext).get(), - rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) : std::nullopt + rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) + : std::nullopt ) ); }); @@ -207,16 +209,17 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeFor1 return run_catching_cxx_exception_or_throws(env, [=] { JavaByteArrayRef key_ref(env, key); - std::array, 1> keys = { key_ref.get() }; + std::array, 1> keys = {key_ref.get()}; - session::DecodeEnvelopeKey decode_key { - .decrypt_keys = std::span(keys.data(), keys.size()), + 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 } }, + std::chrono::sys_time{ + std::chrono::milliseconds{now_epoch_ms}}, *java_to_cpp_array<32>(env, pro_backend_pub_key) )); }); @@ -237,13 +240,14 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeForG 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)); + 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 { + 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()), }; @@ -251,7 +255,8 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeForG return serializeDecodedEnvelope(env, session::decode_envelope( decode_key, JavaByteArrayRef(env, payload).get(), - std::chrono::sys_time { std::chrono::milliseconds { now_epoch_ms } }, + std::chrono::sys_time{ + std::chrono::milliseconds{now_epoch_ms}}, *java_to_cpp_array<32>(env, pro_backend_pub_key) )); }); diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/AddProPayment.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/AddProPayment.kt deleted file mode 100644 index b33eb2b..0000000 --- a/library/src/main/java/network/loki/messenger/libsession_util/pro/AddProPayment.kt +++ /dev/null @@ -1,81 +0,0 @@ -package network.loki.messenger.libsession_util.pro - -import network.loki.messenger.libsession_util.LibSessionUtilCApi - -object AddProPaymentRequests : LibSessionUtilCApi() { - private external fun buildJson( - version: Int, - masterPrivateKey: ByteArray, - rotatingPrivateKey: ByteArray, - paymentProvider: Int, - paymentTransactionId: String, - paymentOrderId: String, - ): String - - fun buildJson( - /** - * Version of the request to build a hash for - */ - version: Int, - /** - * 64-byte libsodium style or 32 byte Ed25519 master private key - */ - masterPrivateKey: ByteArray, - - /** - * 64-byte libsodium style or 32 byte Ed25519 rotating private key - */ - rotatingPrivateKey: ByteArray, - - /** - * Provider that the payment to register is coming from - */ - paymentProvider: PaymentProvider, - - /** - * ID that is associated with the payment from the payment provider - */ - paymentTransactionId: String, - - /** - * Order ID that is associated with the payment - */ - paymentOrderId: String, - - ): String = buildJson( - version = version, - masterPrivateKey = masterPrivateKey, - rotatingPrivateKey = rotatingPrivateKey, - paymentProvider = paymentProvider.nativeValue, - paymentTransactionId = paymentTransactionId, - paymentOrderId = paymentOrderId, - ) -} - - -enum class AddProPaymentError(internal val nativeValue: Int) { - Generic(1), - AlreadyRedeemed(2), - UnknownPayment(3), -} - - - -object AddProPaymentResponses { - fun parse(jsonResponse: String): ProProofResponse { - return when (val r = ProProofResponse.parseRaw(jsonResponse)) { - is ProProofResponse.Failure -> { - ProProofResponse.Failure( - status = AddProPaymentError.entries.firstOrNull { - it.nativeValue == r.status - } ?: AddProPaymentError.Generic, - errors = r.errors, - ) - } - - is ProProofResponse.Success -> { - ProProofResponse.Success(r.proof) - } - } - } -} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/BackendRequests.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/BackendRequests.kt new file mode 100644 index 0000000..67b632c --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/pro/BackendRequests.kt @@ -0,0 +1,39 @@ +package network.loki.messenger.libsession_util.pro + +import androidx.annotation.Keep +import network.loki.messenger.libsession_util.LibSessionUtilCApi + +typealias PaymentProvider = Int + +object BackendRequests : LibSessionUtilCApi() { + const val PAYMENT_PROVIDER_GOOGLE_PLAY: PaymentProvider = 1 + const val PAYMENT_PROVIDER_APP_STORE: PaymentProvider = 2 + + class MasterRotatingSignatures @Keep constructor( + val masterSignature: ByteArray, + val rotatingSignature: ByteArray, + ) + + external fun signAddProPaymentRequest( + version: Int, + masterPrivateKey: ByteArray, + rotatingPrivateKey: ByteArray, + paymentProvider: PaymentProvider, + paymentId: String, + orderId: String, + ): MasterRotatingSignatures + + external fun signGetProProofRequest( + version: Int, + masterPrivateKey: ByteArray, + rotatingPrivateKey: ByteArray, + nowMs: Long, + ): MasterRotatingSignatures + + external fun signGetProStatusRequest( + version: Int, + masterPrivateKey: ByteArray, + nowMs: Long, + count: Int, + ): ByteArray +} diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/GetProProof.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/GetProProof.kt deleted file mode 100644 index e34e660..0000000 --- a/library/src/main/java/network/loki/messenger/libsession_util/pro/GetProProof.kt +++ /dev/null @@ -1,34 +0,0 @@ -package network.loki.messenger.libsession_util.pro - -import network.loki.messenger.libsession_util.LibSessionUtilCApi - -enum class GetProProofError { - Generic, -} - -object GetProProofRequests : LibSessionUtilCApi() { - external fun buildJson( - version: Int, - /** - * 64-byte libsodium style or 32 byte Ed25519 master private key - */ - masterPrivateKey: ByteArray, - - /** - * 64-byte libsodium style or 32 byte Ed25519 rotating private key - */ - rotatingPrivateKey: ByteArray, - nowUnixTs: Long, - ): String -} - -object GetProProofResponses { - fun parse(json: String): ProProofResponse { - return when (val r = ProProofResponse.parseRaw(json)) { - is ProProofResponse.Success -> ProProofResponse.Success(r.proof) - is ProProofResponse.Failure -> { - ProProofResponse.Failure(GetProProofError.Generic, r.errors) - } - } - } -} diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/PaymentProvider.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/PaymentProvider.kt deleted file mode 100644 index cf21f39..0000000 --- a/library/src/main/java/network/loki/messenger/libsession_util/pro/PaymentProvider.kt +++ /dev/null @@ -1,6 +0,0 @@ -package network.loki.messenger.libsession_util.pro - -enum class PaymentProvider(val nativeValue: Int) { - GooglePlayStore(1), - AppleAppStore(2), -} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt index 0d6e3ec..47a438e 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt @@ -1,40 +1,67 @@ package network.loki.messenger.libsession_util.pro -import androidx.annotation.Keep -import network.loki.messenger.libsession_util.LibSessionUtilCApi import java.time.Instant -class ProProof @Keep private constructor(private val nativeValue: Long) { - - val version: Int get() = nativeGetVersion(nativeValue) - val expiry: Instant get() = Instant.ofEpochSecond(nativeGetExpiry(nativeValue)) - val rotatingPubKey: ByteArray get() = nativeGetRotatingPubKey(nativeValue) +class ProProof( + val version: Int, + val genIndexHash: ByteArray, + val rotatingPubKey: ByteArray, + val expiryMs: Long, + val signature: ByteArray +) { + init { + check(rotatingPubKey.size == 32) { + "Rotating public key must be 32 bytes" + } + check(signature.size == 64) { + "Signature must be 64 bytes" + } + } - /** - * Serialize the [ProProof] to a byte array for storage or transmission - */ - fun serialize(): String = nativeSerialize(nativeValue) + enum class Status(internal val nativeValue: Int) { + InvalidProBackendSignature(1), + InvalidUserSignature(2), + Valid(3), + Expired(4), + ; + companion object { + internal fun fromNativeValue(value: Int): Status { + return entries.first { it.nativeValue == value } + } - protected fun finalize() { - nativeDestroy(nativeValue) + internal fun fromNativeValueOrNull(value: Int): Status? { + return entries.firstOrNull { it.nativeValue == value } + } + } } + private external fun status( + verifyPubKey: ByteArray, + nowUnixTs: Long, + signedMessageData: ByteArray?, + signedMessageSignature: ByteArray? + ): Int - companion object : LibSessionUtilCApi() { - private external fun nativeGetVersion(nativeValue: Long): Int - private external fun nativeGetExpiry(nativeValue: Long): Long - private external fun nativeGetRotatingPubKey(nativeValue: Long): ByteArray - private external fun nativeSerialize(nativeValue: Long): String - private external fun nativeDeserialize(data: String): Long - private external fun nativeDestroy(nativeValue: Long) + class ProSignedMessage( + val data: ByteArray, + val signature: ByteArray, + ) - /** - * Deserialize a [ProProof] from a byte array - */ - fun deserialize(data: String): ProProof { - return ProProof(nativeDeserialize(data)) - } + fun status( + verifyPubKey: ByteArray, + signedMessage: ProSignedMessage?, + now: Instant = Instant.now(), + ): Status { + val signedMessageData = signedMessage?.data + val signedMessageSignature = signedMessage?.signature + val statusValue = status( + verifyPubKey = verifyPubKey, + nowUnixTs = now.epochSecond, + signedMessageData = signedMessageData, + signedMessageSignature = signedMessageSignature + ) + return Status.fromNativeValue(statusValue) } } \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProofResponse.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProofResponse.kt deleted file mode 100644 index e32596a..0000000 --- a/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProofResponse.kt +++ /dev/null @@ -1,24 +0,0 @@ -package network.loki.messenger.libsession_util.pro - -import androidx.annotation.Keep -import network.loki.messenger.libsession_util.LibSessionUtilCApi - - -/** - * Represents the response that returns a [ProProof] - */ -sealed interface ProProofResponse { - data class Success @Keep constructor(val proof: ProProof) : ProProofResponse - data class Failure(val status: T, val errors: List) : ProProofResponse - - companion object : LibSessionUtilCApi() { - /** - * Parses a raw JSON string into a [ProProofResponse] with an integer status code. - */ - private external fun nativeParseRaw(json: String): ProProofResponse - - internal fun parseRaw(json: String): ProProofResponse { - return nativeParseRaw(json) - } - } -} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/ResponseStatus.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/ResponseStatus.kt deleted file mode 100644 index 559e642..0000000 --- a/library/src/main/java/network/loki/messenger/libsession_util/pro/ResponseStatus.kt +++ /dev/null @@ -1,5 +0,0 @@ -package network.loki.messenger.libsession_util.pro - -typealias ResponseStatus = Int - -const val RESPONSE_STATUS_SUCCESS: ResponseStatus = 200 \ 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 index 7f8c703..d41dd26 100644 --- 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 @@ -1,18 +1,29 @@ package network.loki.messenger.libsession_util.protocol import androidx.annotation.Keep +import network.loki.messenger.libsession_util.pro.ProProof import network.loki.messenger.libsession_util.util.Bytes +import java.util.EnumSet data class DecodedCommunityMessage( - val proStatus: ProStatus, + val proStatus: ProProof.Status?, + val proProof: ProProof?, val contentPlainText: Bytes, ) { @Keep constructor( - proStatus: ProStatus, + status: Int, + proProof: ProProof?, contentPlainText: ByteArray, ): this( - proStatus = proStatus, + proStatus = ProProof.Status.fromNativeValueOrNull(status), + proProof = proProof, contentPlainText = Bytes(contentPlainText), ) + + init { + check(proProof == null || proStatus in EnumSet.of(ProProof.Status.Expired, ProProof.Status.Valid)) { + "proProof must be null unless proStatus is Expired or Valid" + } + } } diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelope.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelope.kt index 35e1f4d..8b3079d 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelope.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelope.kt @@ -1,12 +1,15 @@ package network.loki.messenger.libsession_util.protocol import androidx.annotation.Keep +import network.loki.messenger.libsession_util.pro.ProProof import network.loki.messenger.libsession_util.util.Bytes import java.time.Instant +import java.util.EnumSet data class DecodedEnvelope( val envelope: Envelope, - val proStatus: ProStatus, + val proStatus: ProProof.Status?, + val proProof: ProProof?, val contentPlainText: Bytes, val senderEd25519PubKey: Bytes, val senderX25519PubKey: Bytes, @@ -15,17 +18,25 @@ data class DecodedEnvelope( @Keep constructor( envelope: Envelope, - proStatus: ProStatus, + proStatus: Int, + proProof: ProProof?, contentPlainText: ByteArray, senderEd25519PubKey: ByteArray, senderX25519PubKey: ByteArray, timestampEpochMills: Long ): this( envelope = envelope, - proStatus = proStatus, + proStatus = ProProof.Status.fromNativeValueOrNull(proStatus), + proProof = proProof, contentPlainText = Bytes(contentPlainText), senderEd25519PubKey = Bytes(senderEd25519PubKey), senderX25519PubKey = Bytes(senderX25519PubKey), timestamp = Instant.ofEpochMilli(timestampEpochMills) ) + + init { + check(proProof == null || proStatus in EnumSet.of(ProProof.Status.Expired, ProProof.Status.Valid)) { + "proProof must be null unless proStatus is Expired or Valid" + } + } } 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 deleted file mode 100644 index 49b6a94..0000000 --- a/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProStatus.kt +++ /dev/null @@ -1,24 +0,0 @@ -package network.loki.messenger.libsession_util.protocol - -import androidx.annotation.Keep -import java.time.Instant - - -sealed interface ProStatus { - data object None : ProStatus - data object Invalid : ProStatus - - data class Valid( - val expiresAt: Instant, - val proFeatures: Set - ) { - @Keep - constructor( - expiresAtEpochMills: Long, - proFeatures: Long - ): this( - expiresAt = Instant.ofEpochMilli(expiresAtEpochMills), - proFeatures = proFeatures.toFeatures() - ) - } -} \ No newline at end of file From 9818bf747fb81a5a06dfad1d49b56e9a1d8f1fcf Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Wed, 12 Nov 2025 14:36:41 +1100 Subject: [PATCH 04/26] Building request json --- library/src/main/cpp/pro_backend.cpp | 75 +++++++------------ .../libsession_util/pro/BackendRequests.kt | 20 ++--- 2 files changed, 36 insertions(+), 59 deletions(-) diff --git a/library/src/main/cpp/pro_backend.cpp b/library/src/main/cpp/pro_backend.cpp index 1f1e0c8..fd9be02 100644 --- a/library/src/main/cpp/pro_backend.cpp +++ b/library/src/main/cpp/pro_backend.cpp @@ -6,76 +6,59 @@ using namespace jni_utils; -static jobject serializeMasterRotatingSignatures( - JNIEnv *env, const session::pro_backend::MasterRotatingSignatures &sigs) { - JavaLocalRef result_class( - env, - env->FindClass( - "network/loki/messenger/libsession_util/pro/BackendRequests$MasterRotatingSignatures")); - - return env->NewObject( - result_class.get(), - env->GetMethodID(result_class.get(), "", "([B[B)V"), - util::bytes_from_span(env, sigs.master_sig), - util::bytes_from_span(env, sigs.rotating_sig) - ); -} - extern "C" -JNIEXPORT jobject JNICALL -Java_network_loki_messenger_libsession_1util_pro_BackendRequests_signAddProPaymentRequest( +JNIEXPORT jstring JNICALL +Java_network_loki_messenger_libsession_1util_pro_BackendRequests_buildAddProPaymentRequestJson( JNIEnv *env, jobject thiz, jint version, jbyteArray master_private_key, jbyteArray rotating_private_key, jint payment_provider, jstring payment_id, jstring order_id) { - return run_catching_cxx_exception_or_throws(env, [=] { - auto sigs = session::pro_backend::AddProPaymentRequest::build_sigs( - static_cast(version), + return run_catching_cxx_exception_or_throws(env, [=]() { + auto json = session::pro_backend::AddProPaymentRequest::build_to_json( + version, JavaByteArrayRef(env, master_private_key).get(), JavaByteArrayRef(env, rotating_private_key).get(), - static_cast( - payment_provider), + static_cast(payment_provider), JavaStringRef(env, payment_id).get_raw(), JavaStringRef(env, order_id).get_raw()); - return serializeMasterRotatingSignatures(env, sigs); + return util::jstringFromOptional(env, json); }); } extern "C" -JNIEXPORT jobject JNICALL -Java_network_loki_messenger_libsession_1util_pro_BackendRequests_signGetProProofRequest(JNIEnv *env, - jobject thiz, - jint version, - jbyteArray master_private_key, - jbyteArray rotating_private_key, - jlong unix_ts_ms) { - return run_catching_cxx_exception_or_throws(env, [=] { - auto sigs = session::pro_backend::GetProProofRequest::build_sigs( +JNIEXPORT jstring JNICALL +Java_network_loki_messenger_libsession_1util_pro_BackendRequests_buildGetProProofRequestJson( + JNIEnv *env, jobject thiz, jint version, jbyteArray master_private_key, + jbyteArray rotating_private_key, jlong now_ms) { + return run_catching_cxx_exception_or_throws(env, [=]() { + auto json = session::pro_backend::GetProProofRequest::build_to_json( version, JavaByteArrayRef(env, master_private_key).get(), JavaByteArrayRef(env, rotating_private_key).get(), - std::chrono::sys_time{ - std::chrono::milliseconds{unix_ts_ms}} + std::chrono::sys_time { + std::chrono::milliseconds(now_ms) + } ); - return serializeMasterRotatingSignatures(env, sigs); + return util::jstringFromOptional(env, json); }); } extern "C" -JNIEXPORT jbyteArray JNICALL -Java_network_loki_messenger_libsession_1util_pro_BackendRequests_signGetProStatusRequest( - JNIEnv *env, jobject thiz, jint version, jbyteArray master_private_key, jlong now_ms, +JNIEXPORT jstring JNICALL +Java_network_loki_messenger_libsession_1util_pro_BackendRequests_buildGetProStatusRequestJson( + JNIEnv *env, jobject thiz, jint version, jbyteArray pro_master_private_key, jlong now_ms, jint count) { - return run_catching_cxx_exception_or_throws(env, [=] { - auto sig = session::pro_backend::GetProStatusRequest::build_sig( - static_cast(version), - JavaByteArrayRef(env, master_private_key).get(), - std::chrono::sys_time{ - std::chrono::milliseconds{now_ms}}, - static_cast(count) + return run_catching_cxx_exception_or_throws(env, [=]() { + auto json = session::pro_backend::GetProStatusRequest::build_to_json( + version, + JavaByteArrayRef(env, pro_master_private_key).get(), + std::chrono::sys_time { + std::chrono::milliseconds(now_ms) + }, + static_cast(count) ); - return util::bytes_from_span(env, sig); + return util::jstringFromOptional(env, json); }); } \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/BackendRequests.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/BackendRequests.kt index 67b632c..89b8230 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/pro/BackendRequests.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/pro/BackendRequests.kt @@ -1,6 +1,5 @@ package network.loki.messenger.libsession_util.pro -import androidx.annotation.Keep import network.loki.messenger.libsession_util.LibSessionUtilCApi typealias PaymentProvider = Int @@ -9,31 +8,26 @@ object BackendRequests : LibSessionUtilCApi() { const val PAYMENT_PROVIDER_GOOGLE_PLAY: PaymentProvider = 1 const val PAYMENT_PROVIDER_APP_STORE: PaymentProvider = 2 - class MasterRotatingSignatures @Keep constructor( - val masterSignature: ByteArray, - val rotatingSignature: ByteArray, - ) - - external fun signAddProPaymentRequest( + external fun buildAddProPaymentRequestJson( version: Int, masterPrivateKey: ByteArray, rotatingPrivateKey: ByteArray, paymentProvider: PaymentProvider, paymentId: String, orderId: String, - ): MasterRotatingSignatures + ): String - external fun signGetProProofRequest( + external fun buildGetProProofRequestJson( version: Int, masterPrivateKey: ByteArray, rotatingPrivateKey: ByteArray, nowMs: Long, - ): MasterRotatingSignatures + ): String - external fun signGetProStatusRequest( + external fun buildGetProStatusRequestJson( version: Int, - masterPrivateKey: ByteArray, + proMasterPrivateKey: ByteArray, nowMs: Long, count: Int, - ): ByteArray + ): String } From f4329737600a2ea247f3922a7f22538d7f875d5b Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Thu, 13 Nov 2025 10:59:12 +1100 Subject: [PATCH 05/26] Renamed --- build.gradle.kts | 1 + gradle/libs.versions.toml | 5 +- library/build.gradle.kts | 2 + library/src/main/cpp/pro_backend.cpp | 4 +- library/src/main/cpp/pro_proof.cpp | 44 ++++------- .../libsession_util/pro/BackendRequests.kt | 4 +- .../messenger/libsession_util/pro/ProProof.kt | 75 +++++++++++++++---- 7 files changed, 84 insertions(+), 51 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index b72fb0b..eb3bad5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,4 +2,5 @@ plugins { alias(libs.plugins.android.library) apply false alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.kotlinx.serialization) apply false } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 69add3c..f1f8436 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agp = "8.13.0" +agp = "8.13.1" kotlin = "2.2.20" [libraries] @@ -8,8 +8,9 @@ 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" } +kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version = "1.9.0" } [plugins] android-library = { id = "com.android.library", version.ref = "agp" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } - +kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } diff --git a/library/build.gradle.kts b/library/build.gradle.kts index 87a9668..1ebac53 100644 --- a/library/build.gradle.kts +++ b/library/build.gradle.kts @@ -3,6 +3,7 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { alias(libs.plugins.android.library) alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlinx.serialization) id("maven-publish") } @@ -119,4 +120,5 @@ dependencies { androidTestImplementation(libs.androidx.test.ext) implementation(libs.androidx.annotations) + implementation(libs.kotlinx.serialization.core) } diff --git a/library/src/main/cpp/pro_backend.cpp b/library/src/main/cpp/pro_backend.cpp index fd9be02..3fe20a3 100644 --- a/library/src/main/cpp/pro_backend.cpp +++ b/library/src/main/cpp/pro_backend.cpp @@ -27,7 +27,7 @@ Java_network_loki_messenger_libsession_1util_pro_BackendRequests_buildAddProPaym extern "C" JNIEXPORT jstring JNICALL -Java_network_loki_messenger_libsession_1util_pro_BackendRequests_buildGetProProofRequestJson( +Java_network_loki_messenger_libsession_1util_pro_BackendRequests_buildGenerateProProofRequestJson( JNIEnv *env, jobject thiz, jint version, jbyteArray master_private_key, jbyteArray rotating_private_key, jlong now_ms) { return run_catching_cxx_exception_or_throws(env, [=]() { @@ -46,7 +46,7 @@ Java_network_loki_messenger_libsession_1util_pro_BackendRequests_buildGetProProo extern "C" JNIEXPORT jstring JNICALL -Java_network_loki_messenger_libsession_1util_pro_BackendRequests_buildGetProStatusRequestJson( +Java_network_loki_messenger_libsession_1util_pro_BackendRequests_buildGetProDetailsRequestJson( JNIEnv *env, jobject thiz, jint version, jbyteArray pro_master_private_key, jlong now_ms, jint count) { return run_catching_cxx_exception_or_throws(env, [=]() { diff --git a/library/src/main/cpp/pro_proof.cpp b/library/src/main/cpp/pro_proof.cpp index 5b4142c..7f90939 100644 --- a/library/src/main/cpp/pro_proof.cpp +++ b/library/src/main/cpp/pro_proof.cpp @@ -10,34 +10,18 @@ using namespace jni_utils; extern "C" JNIEXPORT jint JNICALL -Java_network_loki_messenger_libsession_1util_pro_ProProof_status(JNIEnv *env, jobject thiz, - jbyteArray verify_pub_key, - jlong now_unix_ts, - jbyteArray signed_message_data, - jbyteArray signed_message_signature) { +Java_network_loki_messenger_libsession_1util_pro_ProProof_00024Companion_nativeStatus(JNIEnv *env, + jobject thiz, + jint version, + jbyteArray gen_index_hash, + jbyteArray rotating_pub_key, + jlong expiry_ms, + jbyteArray signature, + jlong now_unix_ts, + jbyteArray verify_pub_key, + jbyteArray signed_message_data, + jbyteArray signed_message_signature) { return run_catching_cxx_exception_or_throws(env, [=]() { - JavaLocalRef clazz(env, env->GetObjectClass(thiz)); - auto get_version_method = env->GetMethodID(clazz.get(), "getVersion", "()I"); - auto get_gen_index_hash_method = env->GetMethodID(clazz.get(), "getGenIndexHash", "()[B"); - auto get_rotating_pub_key_method = env->GetMethodID(clazz.get(), "getRotatingPubKey", - "()[B"); - auto get_expiry_method = env->GetMethodID(clazz.get(), "getExpiryMs", "()J"); - auto get_signature_method = env->GetMethodID(clazz.get(), "getSignature", "()[B"); - - auto version = env->CallIntMethod(thiz, get_version_method); - JavaLocalRef gen_index_hash_bytes_obj(env, - static_cast(env->CallObjectMethod( - thiz, - get_gen_index_hash_method))); - JavaLocalRef rotating_pub_key_bytes_obj(env, - static_cast(env->CallObjectMethod( - thiz, - get_rotating_pub_key_method))); - auto expiry_ms = env->CallLongMethod(thiz, get_expiry_method); - JavaLocalRef signature_bytes_obj(env, - static_cast(env->CallObjectMethod( - thiz, get_signature_method))); - std::optional signed_msg; JavaByteArrayRef signed_message_data_ref(env, signed_message_data); JavaByteArrayRef signed_message_signature_ref(env, signed_message_signature); @@ -51,11 +35,11 @@ Java_network_loki_messenger_libsession_1util_pro_ProProof_status(JNIEnv *env, jo session::ProProof pro_proof { .version = static_cast(version), - .gen_index_hash = *java_to_cpp_array<32>(env, gen_index_hash_bytes_obj.get()), - .rotating_pubkey = *java_to_cpp_array<32>(env, rotating_pub_key_bytes_obj.get()), + .gen_index_hash = *java_to_cpp_array<32>(env, gen_index_hash), + .rotating_pubkey = *java_to_cpp_array<32>(env, rotating_pub_key), .expiry_unix_ts = std::chrono::sys_time( std::chrono::milliseconds(expiry_ms)), - .sig = *java_to_cpp_array<64>(env, signature_bytes_obj.get()), + .sig = *java_to_cpp_array<64>(env, signature), }; return static_cast(pro_proof.status( diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/BackendRequests.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/BackendRequests.kt index 89b8230..6a4b60b 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/pro/BackendRequests.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/pro/BackendRequests.kt @@ -17,14 +17,14 @@ object BackendRequests : LibSessionUtilCApi() { orderId: String, ): String - external fun buildGetProProofRequestJson( + external fun buildGenerateProProofRequestJson( version: Int, masterPrivateKey: ByteArray, rotatingPrivateKey: ByteArray, nowMs: Long, ): String - external fun buildGetProStatusRequestJson( + external fun buildGetProDetailsRequestJson( version: Int, proMasterPrivateKey: ByteArray, nowMs: Long, diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt index 47a438e..e7259a8 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt @@ -1,20 +1,52 @@ package network.loki.messenger.libsession_util.pro +import androidx.annotation.Keep +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import java.time.Instant -class ProProof( +/** + * Represents a proof of Pro. This class is marked as @Serializable to represent the JSON structure + * received from the Pro Backend. + */ +@Serializable +data class ProProof( val version: Int, - val genIndexHash: ByteArray, - val rotatingPubKey: ByteArray, + + @SerialName("gen_index_hash") + val genIndexHashHex: String, + + @SerialName("rotating_pkey") + val rotatingPubKeyHex: String, + + @SerialName("expiry_unix_ts_ms") val expiryMs: Long, - val signature: ByteArray + + @SerialName("sig") + val signatureHex: String ) { + @Keep + constructor( + version: Int, + genIndexHash: ByteArray, + rotatingPubKey: ByteArray, + expiryMs: Long, + signature: ByteArray + ): this( + version = version, + genIndexHashHex = genIndexHash.toHexString(), + rotatingPubKeyHex = rotatingPubKey.toHexString(), + expiryMs = expiryMs, + signatureHex = signature.toHexString() + ) + + init { - check(rotatingPubKey.size == 32) { + check(rotatingPubKeyHex.length == 64) { "Rotating public key must be 32 bytes" } - check(signature.size == 64) { + check(signatureHex.length == 128) { "Signature must be 64 bytes" } } @@ -37,13 +69,6 @@ class ProProof( } } - private external fun status( - verifyPubKey: ByteArray, - nowUnixTs: Long, - signedMessageData: ByteArray?, - signedMessageSignature: ByteArray? - ): Int - class ProSignedMessage( val data: ByteArray, val signature: ByteArray, @@ -56,12 +81,32 @@ class ProProof( ): Status { val signedMessageData = signedMessage?.data val signedMessageSignature = signedMessage?.signature - val statusValue = status( + val statusValue = nativeStatus( + version = version, + genIndexHash = genIndexHashHex.hexToByteArray(), + rotatingPubKey = rotatingPubKeyHex.hexToByteArray(), + expiryMs = expiryMs, + signature = signatureHex.hexToByteArray(), + nowUnixTs = now.toEpochMilli(), verifyPubKey = verifyPubKey, - nowUnixTs = now.epochSecond, signedMessageData = signedMessageData, signedMessageSignature = signedMessageSignature ) + return Status.fromNativeValue(statusValue) } + + companion object { + private external fun nativeStatus( + version: Int, + genIndexHash: ByteArray, + rotatingPubKey: ByteArray, + expiryMs: Long, + signature: ByteArray, + nowUnixTs: Long, + verifyPubKey: ByteArray, + signedMessageData: ByteArray?, + signedMessageSignature: ByteArray? + ): Int + } } \ No newline at end of file From eadc1a4f7c16d1a231817998d5abc153ffedcbb7 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Thu, 13 Nov 2025 16:14:18 +1100 Subject: [PATCH 06/26] Pro features --- library/src/main/cpp/protocol.cpp | 6 ++++-- .../protocol/DecodedCommunityMessage.kt | 3 +++ .../protocol/DecodedEnvelope.kt | 3 +++ .../libsession_util/protocol/ProFeatures.kt | 18 ++++++++++++++++++ 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/library/src/main/cpp/protocol.cpp b/library/src/main/cpp/protocol.cpp index 02493e5..f55bf62 100644 --- a/library/src/main/cpp/protocol.cpp +++ b/library/src/main/cpp/protocol.cpp @@ -53,7 +53,7 @@ static jobject serializeDecodedEnvelope(JNIEnv *env, const session::DecodedEnvel jmethodID init = env->GetMethodID( envelopClass.get(), "", - "(Lnetwork/loki/messenger/libsession_util/protocol/Envelope;Lnetwork/loki/messenger/libsession_util/pro/ProProof$Status;Lnetwork/loki/messenger/libsession_util/pro/ProProof;[B[B[BJ)V" + "(Lnetwork/loki/messenger/libsession_util/protocol/Envelope;ILnetwork/loki/messenger/libsession_util/pro/ProProof;J[B[B[BJ)V" ); return env->NewObject(envelopClass.get(), init, @@ -61,6 +61,7 @@ static jobject serializeDecodedEnvelope(JNIEnv *env, const session::DecodedEnvel envelop.pro ? static_cast(envelop.pro->status) : static_cast(-1), envelop.pro ? serializeProProof(env, envelop.pro->proof).get() : nullptr, + static_cast(envelop.pro ? envelop.pro->features : 0), content.get(), sender_ed25519.get(), sender_x25519.get(), @@ -165,7 +166,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeForC jmethodID init = env->GetMethodID( envelopClass.get(), "", - "(Lnetwork/loki/messenger/libsession_util/protocol/pro/ProProof$Status;Lnetwork/loki/messenger/libsession_util/protocol/pro/ProProof;[B)V" + "(Lnetwork/loki/messenger/libsession_util/protocol/pro/ProProof$Status;Lnetwork/loki/messenger/libsession_util/protocol/pro/ProProof;J[B)V" ); return env->NewObject( @@ -174,6 +175,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeForC decoded.pro ? static_cast(decoded.pro->status) : static_cast(-1), decoded.pro ? serializeProProof(env, decoded.pro->proof).get() : nullptr, + static_cast(decoded.pro ? decoded.pro->features : 0), util::bytes_from_vector(env, decoded.content_plaintext) ); }); 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 index d41dd26..1779c48 100644 --- 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 @@ -8,16 +8,19 @@ import java.util.EnumSet data class DecodedCommunityMessage( val proStatus: ProProof.Status?, val proProof: ProProof?, + val proFeatures: ProFeatures, val contentPlainText: Bytes, ) { @Keep constructor( status: Int, proProof: ProProof?, + proFeatures: Long, contentPlainText: ByteArray, ): this( proStatus = ProProof.Status.fromNativeValueOrNull(status), proProof = proProof, + proFeatures = ProFeatures(proFeatures), contentPlainText = Bytes(contentPlainText), ) diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelope.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelope.kt index 8b3079d..5cce811 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelope.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelope.kt @@ -10,6 +10,7 @@ data class DecodedEnvelope( val envelope: Envelope, val proStatus: ProProof.Status?, val proProof: ProProof?, + val proFeatures: ProFeatures, val contentPlainText: Bytes, val senderEd25519PubKey: Bytes, val senderX25519PubKey: Bytes, @@ -20,6 +21,7 @@ data class DecodedEnvelope( envelope: Envelope, proStatus: Int, proProof: ProProof?, + proFeatures: Long, contentPlainText: ByteArray, senderEd25519PubKey: ByteArray, senderX25519PubKey: ByteArray, @@ -28,6 +30,7 @@ data class DecodedEnvelope( envelope = envelope, proStatus = ProProof.Status.fromNativeValueOrNull(proStatus), proProof = proProof, + proFeatures = ProFeatures(proFeatures), contentPlainText = Bytes(contentPlainText), senderEd25519PubKey = Bytes(senderEd25519PubKey), senderX25519PubKey = Bytes(senderX25519PubKey), 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 index 843be42..e52b733 100644 --- 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 @@ -1,5 +1,7 @@ package network.loki.messenger.libsession_util.protocol +import kotlinx.serialization.Serializable + enum class ProFeature(internal val bitIndex: Int) { HIGHER_CHARACTER_LIMIT(0), @@ -7,6 +9,22 @@ enum class ProFeature(internal val bitIndex: Int) { ANIMATED_AVATAR(2), } +@Serializable +@JvmInline +value class ProFeatures(val rawValue: Long) { + companion object { + val NONE = ProFeatures(0L) + } + + fun contains(feature: ProFeature): Boolean { + return (rawValue and (1L shl feature.bitIndex)) != 0L + } + + fun toSet(): Set { + return rawValue.toFeatures() + } +} + internal fun Long.toFeatures(): Set { return buildSet(ProFeature.entries.size) { for (entry in ProFeature.entries) { From c2b60dc64ee2501613329de30e9b51e16208f8de Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Fri, 14 Nov 2025 11:20:10 +1100 Subject: [PATCH 07/26] Fix issue with pro master key generation --- library/src/main/cpp/ed25519.cpp | 2 +- .../main/java/network/loki/messenger/libsession_util/ED25519.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/src/main/cpp/ed25519.cpp b/library/src/main/cpp/ed25519.cpp index 62c315e..a842dd6 100644 --- a/library/src/main/cpp/ed25519.cpp +++ b/library/src/main/cpp/ed25519.cpp @@ -47,7 +47,7 @@ Java_network_loki_messenger_libsession_1util_ED25519_generate(JNIEnv *env, jobje extern "C" JNIEXPORT jbyteArray JNICALL -Java_network_loki_messenger_libsession_1util_ED25519_generateProKeyPair(JNIEnv *env, jobject thiz, +Java_network_loki_messenger_libsession_1util_ED25519_generateProMasterKey(JNIEnv *env, jobject thiz, jbyteArray ed25519_seed) { return jni_utils::run_catching_cxx_exception_or_throws(env, [=] { return util::bytes_from_span( diff --git a/library/src/main/java/network/loki/messenger/libsession_util/ED25519.kt b/library/src/main/java/network/loki/messenger/libsession_util/ED25519.kt index a9aff66..b2fe435 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/ED25519.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/ED25519.kt @@ -37,5 +37,5 @@ object ED25519 : LibSessionUtilCApi() { * @param ed25519Seed The seed the user uses to generate their session id * @return The libsodium-style Master Session Pro Ed25519 secret key, 64 bytes. */ - external fun generateProPrivateKey(ed25519Seed: ByteArray): ByteArray + external fun generateProMasterKey(ed25519Seed: ByteArray): ByteArray } \ No newline at end of file From 76fbee7a6b325bd830995ca7c39f93227d386ab5 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Fri, 14 Nov 2025 15:01:09 +1100 Subject: [PATCH 08/26] Fixed crash on decoding community messages --- 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 f55bf62..0fc5c9d 100644 --- a/library/src/main/cpp/protocol.cpp +++ b/library/src/main/cpp/protocol.cpp @@ -166,7 +166,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeForC jmethodID init = env->GetMethodID( envelopClass.get(), "", - "(Lnetwork/loki/messenger/libsession_util/protocol/pro/ProProof$Status;Lnetwork/loki/messenger/libsession_util/protocol/pro/ProProof;J[B)V" + "(ILnetwork/loki/messenger/libsession_util/pro/ProProof;J[B)V" ); return env->NewObject( From a1e5a232566855a3e815e294c9bfd0b210b15e27 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Fri, 14 Nov 2025 15:35:08 +1100 Subject: [PATCH 09/26] Update to latest libsession --- library/src/main/cpp/pro_backend.cpp | 4 ++-- libsession-util | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/src/main/cpp/pro_backend.cpp b/library/src/main/cpp/pro_backend.cpp index 3fe20a3..8abdd20 100644 --- a/library/src/main/cpp/pro_backend.cpp +++ b/library/src/main/cpp/pro_backend.cpp @@ -31,7 +31,7 @@ Java_network_loki_messenger_libsession_1util_pro_BackendRequests_buildGeneratePr JNIEnv *env, jobject thiz, jint version, jbyteArray master_private_key, jbyteArray rotating_private_key, jlong now_ms) { return run_catching_cxx_exception_or_throws(env, [=]() { - auto json = session::pro_backend::GetProProofRequest::build_to_json( + auto json = session::pro_backend::GenerateProProofRequest::build_to_json( version, JavaByteArrayRef(env, master_private_key).get(), JavaByteArrayRef(env, rotating_private_key).get(), @@ -50,7 +50,7 @@ Java_network_loki_messenger_libsession_1util_pro_BackendRequests_buildGetProDeta JNIEnv *env, jobject thiz, jint version, jbyteArray pro_master_private_key, jlong now_ms, jint count) { return run_catching_cxx_exception_or_throws(env, [=]() { - auto json = session::pro_backend::GetProStatusRequest::build_to_json( + auto json = session::pro_backend::GetProDetailsRequest::build_to_json( version, JavaByteArrayRef(env, pro_master_private_key).get(), std::chrono::sys_time { diff --git a/libsession-util b/libsession-util index 6134c47..4945c20 160000 --- a/libsession-util +++ b/libsession-util @@ -1 +1 @@ -Subproject commit 6134c4718ae094be53deeb2b4285bed475b20b88 +Subproject commit 4945c20c6d809b194eef2059d82ea1bedab00ced From 49bee28bf2a4d322d5e5e0038316aae2d41900ac Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Mon, 17 Nov 2025 13:37:25 +1100 Subject: [PATCH 10/26] Added ways to convert x25519 -> ed25519 key --- library/src/main/cpp/ed25519.cpp | 14 ++++++++++++++ .../loki/messenger/libsession_util/ED25519.kt | 9 +++++++++ .../messenger/libsession_util/pro/ProProof.kt | 15 +++++++++++---- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/library/src/main/cpp/ed25519.cpp b/library/src/main/cpp/ed25519.cpp index a842dd6..1f1c2eb 100644 --- a/library/src/main/cpp/ed25519.cpp +++ b/library/src/main/cpp/ed25519.cpp @@ -2,6 +2,7 @@ #include "util.h" #include +#include extern "C" JNIEXPORT jbyteArray JNICALL @@ -58,4 +59,17 @@ Java_network_loki_messenger_libsession_1util_ED25519_generateProMasterKey(JNIEnv ); }); +} + +extern "C" +JNIEXPORT jbyteArray JNICALL +Java_network_loki_messenger_libsession_1util_ED25519_positiveEd25519PubKeyFromCurve25519( + JNIEnv *env, jobject thiz, jbyteArray curve25519_pub_key) { + return jni_utils::run_catching_cxx_exception_or_throws(env, [=] { + return util::bytes_from_span( + env, + session::xed25519::pubkey( + jni_utils::JavaByteArrayRef(env, curve25519_pub_key).get()) + ); + }); } \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/ED25519.kt b/library/src/main/java/network/loki/messenger/libsession_util/ED25519.kt index b2fe435..172f392 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/ED25519.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/ED25519.kt @@ -38,4 +38,13 @@ object ED25519 : LibSessionUtilCApi() { * @return The libsodium-style Master Session Pro Ed25519 secret key, 64 bytes. */ external fun generateProMasterKey(ed25519Seed: ByteArray): ByteArray + + private external fun positiveEd25519PubKeyFromCurve25519(curve25519PubKey: ByteArray): ByteArray + + fun ed25519PubKeysFromCurve25519(curve25519PubKey: ByteArray): List { + val positive = positiveEd25519PubKeyFromCurve25519(curve25519PubKey) + val negative = positive.clone() + negative[31] = (negative[31].toInt() xor 0x80).toByte() + return listOf(positive, negative) + } } \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt index e7259a8..1c9d1e7 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt @@ -74,10 +74,17 @@ data class ProProof( val signature: ByteArray, ) + /** + * Checks the status of the Pro proof. + * + * @param senderED25519PubKey The sender (proof generator)'s ED25519 public key. + * @param signedMessage An optional signed message to verify against the proof. + * @param now The current time to use for expiry checks. Defaults to + */ fun status( - verifyPubKey: ByteArray, - signedMessage: ProSignedMessage?, - now: Instant = Instant.now(), + senderED25519PubKey: ByteArray, + now: Instant, + signedMessage: ProSignedMessage? = null, ): Status { val signedMessageData = signedMessage?.data val signedMessageSignature = signedMessage?.signature @@ -88,7 +95,7 @@ data class ProProof( expiryMs = expiryMs, signature = signatureHex.hexToByteArray(), nowUnixTs = now.toEpochMilli(), - verifyPubKey = verifyPubKey, + verifyPubKey = senderED25519PubKey, signedMessageData = signedMessageData, signedMessageSignature = signedMessageSignature ) From 2c548d4fbb9da9bba3eeb63181ba2a1d0934fdd2 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Tue, 18 Nov 2025 10:28:30 +1100 Subject: [PATCH 11/26] Message pro features --- .../protocol/SessionProtocolTest.kt | 23 ++++++++++++ library/src/main/cpp/jni_utils.h | 31 ++++++++++++++++ library/src/main/cpp/protocol.cpp | 25 +++++++++++++ .../libsession_util/protocol/ProFeatures.kt | 4 ++ .../protocol/ProFeaturesForMsg.kt | 37 +++++++++++++++++++ .../protocol/SessionProtocol.kt | 13 +++++++ 6 files changed, 133 insertions(+) create mode 100644 library/src/androidTest/kotlin/network/loki/messenger/libsession_util/protocol/SessionProtocolTest.kt create mode 100644 library/src/main/java/network/loki/messenger/libsession_util/protocol/ProFeaturesForMsg.kt diff --git a/library/src/androidTest/kotlin/network/loki/messenger/libsession_util/protocol/SessionProtocolTest.kt b/library/src/androidTest/kotlin/network/loki/messenger/libsession_util/protocol/SessionProtocolTest.kt new file mode 100644 index 0000000..ff6c1c2 --- /dev/null +++ b/library/src/androidTest/kotlin/network/loki/messenger/libsession_util/protocol/SessionProtocolTest.kt @@ -0,0 +1,23 @@ +package network.loki.messenger.libsession_util.protocol + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class SessionProtocolTest { + + @Test + fun proFeaturesForMessageWorks() { + val proposedFeatures = ProFeatures.from(listOf(ProFeature.PRO_BADGE)) + val result = SessionProtocol.proFeaturesForMessage( + messageBody = "Hello, Session Pro!", + proposedFeatures + ) + + assertEquals(ProFeaturesForMsg.Status.Success, result.status) + assertEquals(19, result.codepointCount) + assertEquals(proposedFeatures, result.features) + } +} \ No newline at end of file diff --git a/library/src/main/cpp/jni_utils.h b/library/src/main/cpp/jni_utils.h index 87399ff..75a6d72 100644 --- a/library/src/main/cpp/jni_utils.h +++ b/library/src/main/cpp/jni_utils.h @@ -200,6 +200,37 @@ namespace jni_utils { } }; + class JavaCharsRef { + JNIEnv *env; + jstring s; + std::span data; + + public: + JavaCharsRef(JNIEnv *env, jstring s) : env(env), s(s) { + const jchar *c_str = env->GetStringChars(s, nullptr); + data = std::span(const_cast(c_str), env->GetStringLength(s)); + } + + JavaCharsRef(const JavaCharsRef &) = delete; + + ~JavaCharsRef() { + env->ReleaseStringChars(s, data.data()); + } + + const jchar* chars() const { + return data.data(); + } + + size_t size() const { + return data.size(); + } + + // Get the data as a span. Only valid during the lifetime of this object. + std::span get() const { + return data; + } + }; + /** * A RAII wrapper for a Java byte array. This will automatically release the byte array when it goes out of scope. */ diff --git a/library/src/main/cpp/protocol.cpp b/library/src/main/cpp/protocol.cpp index 0fc5c9d..3eb7729 100644 --- a/library/src/main/cpp/protocol.cpp +++ b/library/src/main/cpp/protocol.cpp @@ -262,4 +262,29 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeForG *java_to_cpp_array<32>(env, pro_backend_pub_key) )); }); +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_proFeaturesForMessage( + JNIEnv *env, jobject thiz, jstring message_body, jlong proposed_features) { + return run_catching_cxx_exception_or_throws(env, [=] { + JavaCharsRef message_ref(env, message_body); + + auto features = session::pro_features_for_utf16( + reinterpret_cast(message_ref.chars()), + message_ref.size(), + static_cast(proposed_features) + ); + + auto clazz = env->FindClass("network/loki/messenger/libsession_util/protocol/ProFeaturesForMsg"); + return env->NewObject( + clazz, + env->GetMethodID(clazz, "", "(ILjava/lang/String;JI)V"), + static_cast(features.status), + features.error.empty() ? nullptr : env->NewStringUTF(std::string(features.error).c_str()), + static_cast(features.features), + static_cast(features.codepoint_count) + ); + }); } \ 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 index e52b733..32ab7dc 100644 --- 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 @@ -14,6 +14,10 @@ enum class ProFeature(internal val bitIndex: Int) { value class ProFeatures(val rawValue: Long) { companion object { val NONE = ProFeatures(0L) + + fun from(features: Collection): ProFeatures { + return ProFeatures(features.toLong()) + } } fun contains(feature: ProFeature): Boolean { diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProFeaturesForMsg.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProFeaturesForMsg.kt new file mode 100644 index 0000000..8a6dfce --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProFeaturesForMsg.kt @@ -0,0 +1,37 @@ +package network.loki.messenger.libsession_util.protocol + +import androidx.annotation.Keep + +/** + * Represents the result of trying to augment a message with Pro features. + * + * @param status The status of the augmentation attempt. + * @param error An optional error message if the augmentation failed. + * @param features The Pro features that were successfully applied. + * @param codepointCount The number of codepoints in the message + */ +data class ProFeaturesForMsg( + val status: Status, + val error: String?, + val features: ProFeatures, + val codepointCount: Int, +) { + @Keep + constructor( + statusNativeValue: Int, + error: String?, + featuresNativeValue: Long, + codepointCount: Int, + ) : this( + status = Status.entries.first { it.nativeValue == statusNativeValue }, + error = error, + features = ProFeatures(featuresNativeValue), + codepointCount = codepointCount, + ) + + enum class Status(internal val nativeValue: Int) { + Success(0), + UTFDecodingError(1), + ExceedsCharacterLimit(2), + } +} 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 3d18b85..fa36dd0 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 @@ -55,4 +55,17 @@ object SessionProtocol : LibSessionUtilCApi() { groupEd25519PrivateKeys: Array, // all available group private keys proBackendPubKey: ByteArray, // 32 bytes backend key ): DecodedEnvelope + + private external fun proFeaturesForMessage( + messageBody: String, + proposedFeatures: Long + ): ProFeaturesForMsg + + /** + * Determines which Pro features shall be applied to a message based on its content and the proposed features. + */ + fun proFeaturesForMessage( + messageBody: String, + proposedFeatures: ProFeatures + ): ProFeaturesForMsg = proFeaturesForMessage(messageBody, proposedFeatures.rawValue) } \ No newline at end of file From 01bceb90affec70233c54a932973ad2a4e297fca Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Tue, 18 Nov 2025 14:08:42 +1100 Subject: [PATCH 12/26] Added provider metadata --- .../protocol/BackendRequestsTest.kt | 17 ++++++++++++ library/src/main/cpp/pro_backend.cpp | 27 +++++++++++++++++++ .../libsession_util/pro/BackendRequests.kt | 3 +++ .../protocol/PaymentProviderMetadata.kt | 15 +++++++++++ .../protocol/SessionProtocol.kt | 1 + 5 files changed, 63 insertions(+) create mode 100644 library/src/androidTest/kotlin/network/loki/messenger/libsession_util/protocol/BackendRequestsTest.kt create mode 100644 library/src/main/java/network/loki/messenger/libsession_util/protocol/PaymentProviderMetadata.kt diff --git a/library/src/androidTest/kotlin/network/loki/messenger/libsession_util/protocol/BackendRequestsTest.kt b/library/src/androidTest/kotlin/network/loki/messenger/libsession_util/protocol/BackendRequestsTest.kt new file mode 100644 index 0000000..03233ca --- /dev/null +++ b/library/src/androidTest/kotlin/network/loki/messenger/libsession_util/protocol/BackendRequestsTest.kt @@ -0,0 +1,17 @@ +package network.loki.messenger.libsession_util.protocol + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import network.loki.messenger.libsession_util.pro.BackendRequests +import org.junit.Assert.assertNotNull +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class BackendRequestsTest { + + @Test + fun getProviderMetadataWorks() { + val metadata = BackendRequests.getPaymentProviderMetadata(BackendRequests.PAYMENT_PROVIDER_GOOGLE_PLAY) + assertNotNull(metadata) + } +} \ No newline at end of file diff --git a/library/src/main/cpp/pro_backend.cpp b/library/src/main/cpp/pro_backend.cpp index 8abdd20..e4127cc 100644 --- a/library/src/main/cpp/pro_backend.cpp +++ b/library/src/main/cpp/pro_backend.cpp @@ -61,4 +61,31 @@ Java_network_loki_messenger_libsession_1util_pro_BackendRequests_buildGetProDeta return util::jstringFromOptional(env, json); }); +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_network_loki_messenger_libsession_1util_pro_BackendRequests_getPaymentProviderMetadata( + JNIEnv *env, jobject thiz, jint payment_provider) { + return run_catching_cxx_exception_or_throws(env, [=]() -> jobject { + if (payment_provider >= SESSION_PRO_BACKEND_PAYMENT_PROVIDER_COUNT || payment_provider < 0) { + return nullptr; + } + + const auto & metadata = SESSION_PRO_BACKEND_PAYMENT_PROVIDER_METADATA[payment_provider]; + auto clazz = env->FindClass("network/loki/messenger/libsession_util/protocol/PaymentProviderMetadata"); + return env->NewObject( + clazz, + env->GetMethodID(clazz, "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"), + util::jstringFromOptional(env, std::string_view(metadata.device.data, metadata.device.size)), + util::jstringFromOptional(env, std::string_view(metadata.store.data, metadata.store.size)), + util::jstringFromOptional(env, std::string_view(metadata.platform.data, metadata.platform.size)), + util::jstringFromOptional(env, std::string_view(metadata.platform_account.data, metadata.platform_account.size)), + util::jstringFromOptional(env, std::string_view(metadata.refund_url.data, metadata.refund_url.size)), + util::jstringFromOptional(env, std::string_view(metadata.refund_after_platform_deadline_url.data, metadata.refund_after_platform_deadline_url.size)), + util::jstringFromOptional(env, std::string_view(metadata.refund_support_url.data, metadata.refund_support_url.size)), + util::jstringFromOptional(env, std::string_view(metadata.update_subscription_url.data, metadata.update_subscription_url.size)), + util::jstringFromOptional(env, std::string_view(metadata.cancel_subscription_url.data, metadata.cancel_subscription_url.size)) + ); + }); } \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/BackendRequests.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/BackendRequests.kt index 6a4b60b..a76e9d0 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/pro/BackendRequests.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/pro/BackendRequests.kt @@ -1,6 +1,7 @@ package network.loki.messenger.libsession_util.pro import network.loki.messenger.libsession_util.LibSessionUtilCApi +import network.loki.messenger.libsession_util.protocol.PaymentProviderMetadata typealias PaymentProvider = Int @@ -30,4 +31,6 @@ object BackendRequests : LibSessionUtilCApi() { nowMs: Long, count: Int, ): String + + external fun getPaymentProviderMetadata(paymentProvider: PaymentProvider): PaymentProviderMetadata? } diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/PaymentProviderMetadata.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/PaymentProviderMetadata.kt new file mode 100644 index 0000000..0a9a32e --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/PaymentProviderMetadata.kt @@ -0,0 +1,15 @@ +package network.loki.messenger.libsession_util.protocol + +import androidx.annotation.Keep + +data class PaymentProviderMetadata @Keep constructor( + val device: String, + val store: String, + val platform: String, + val platformAccount: String, + val refundUrl: String, + val refundAfterPlatformDeadlineUrl: String, + val refundSupportUrl: String, + val updateSubscriptionUrl: String, + val cancelSubscriptionUrl: String, +) \ 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 fa36dd0..5566420 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 @@ -1,6 +1,7 @@ package network.loki.messenger.libsession_util.protocol import network.loki.messenger.libsession_util.LibSessionUtilCApi +import network.loki.messenger.libsession_util.pro.PaymentProvider object SessionProtocol : LibSessionUtilCApi() { external fun encodeFor1o1( From d680da48689e9bc827dbfd576162736facea4599 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Thu, 20 Nov 2025 09:47:40 +1100 Subject: [PATCH 13/26] Added binding to utf16 truncate --- library/src/main/cpp/util.cpp | 15 +++++++++++++++ .../messenger/libsession_util/util/ConfigPush.kt | 3 +++ .../messenger/libsession_util/util/KeyPair.kt | 9 +++++++++ .../libsession_util/util/{Utils.kt => UserPic.kt} | 9 +-------- .../loki/messenger/libsession_util/util/Util.kt | 10 ++++++++++ libsession-util | 2 +- 6 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 library/src/main/java/network/loki/messenger/libsession_util/util/ConfigPush.kt create mode 100644 library/src/main/java/network/loki/messenger/libsession_util/util/KeyPair.kt rename library/src/main/java/network/loki/messenger/libsession_util/util/{Utils.kt => UserPic.kt} (59%) create mode 100644 library/src/main/java/network/loki/messenger/libsession_util/util/Util.kt diff --git a/library/src/main/cpp/util.cpp b/library/src/main/cpp/util.cpp index 36297cb..ed08fa0 100644 --- a/library/src/main/cpp/util.cpp +++ b/library/src/main/cpp/util.cpp @@ -323,3 +323,18 @@ Java_network_loki_messenger_libsession_1util_Config_free(JNIEnv *env, jobject th delete config; } } + +extern "C" +JNIEXPORT jint JNICALL +Java_network_loki_messenger_libsession_1util_util_Util_lengthForCodepoints(JNIEnv *env, + jobject thiz, + jstring str, + jint max_codepoints) { + return jni_utils::run_catching_cxx_exception_or_throws(env, [=]() { + jni_utils::JavaCharsRef str_ref(env, str); + return session::utf16_len_for_codepoints( + { reinterpret_cast(str_ref.chars()), str_ref.size() }, + max_codepoints + ); + }); +} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/util/ConfigPush.kt b/library/src/main/java/network/loki/messenger/libsession_util/util/ConfigPush.kt new file mode 100644 index 0000000..1da7dff --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/util/ConfigPush.kt @@ -0,0 +1,3 @@ +package network.loki.messenger.libsession_util.util + +data class ConfigPush(val messages: List, val seqNo: Long, val obsoleteHashes: List) \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/util/KeyPair.kt b/library/src/main/java/network/loki/messenger/libsession_util/util/KeyPair.kt new file mode 100644 index 0000000..03945c8 --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/util/KeyPair.kt @@ -0,0 +1,9 @@ +package network.loki.messenger.libsession_util.util + +import androidx.annotation.Keep + +data class KeyPair(val pubKey: Bytes, val secretKey: Bytes) { + @Keep + constructor(pubKey: ByteArray, secretKey: ByteArray) + : this(Bytes(pubKey), Bytes(secretKey)) +} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/util/Utils.kt b/library/src/main/java/network/loki/messenger/libsession_util/util/UserPic.kt similarity index 59% rename from library/src/main/java/network/loki/messenger/libsession_util/util/Utils.kt rename to library/src/main/java/network/loki/messenger/libsession_util/util/UserPic.kt index a19e747..02f8d20 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/util/Utils.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/util/UserPic.kt @@ -1,7 +1,5 @@ package network.loki.messenger.libsession_util.util -data class ConfigPush(val messages: List, val seqNo: Long, val obsoleteHashes: List) - data class UserPic(val url: String, val key: Bytes) { constructor(url: String, key: ByteArray) :this(url, Bytes(key)) @@ -13,9 +11,4 @@ data class UserPic(val url: String, val key: Bytes) { // Convenience method to get the key as a ByteArray from native side val keyAsByteArray: ByteArray get() = key.data -} - -data class KeyPair(val pubKey: Bytes, val secretKey: Bytes) { - constructor(pubKey: ByteArray, secretKey: ByteArray) - : this(Bytes(pubKey), Bytes(secretKey)) -} +} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/util/Util.kt b/library/src/main/java/network/loki/messenger/libsession_util/util/Util.kt new file mode 100644 index 0000000..9d565ab --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/util/Util.kt @@ -0,0 +1,10 @@ +package network.loki.messenger.libsession_util.util + +import network.loki.messenger.libsession_util.LibSessionUtilCApi + +object Util : LibSessionUtilCApi() { + private external fun lengthForCodepoints(str: String, maxCodepoints: Int): Int + + fun truncateCodepoints(str: String, maxCodepoints: Int): String = + str.take(lengthForCodepoints(str, maxCodepoints)) +} \ No newline at end of file diff --git a/libsession-util b/libsession-util index 4945c20..2d910d7 160000 --- a/libsession-util +++ b/libsession-util @@ -1 +1 @@ -Subproject commit 4945c20c6d809b194eef2059d82ea1bedab00ced +Subproject commit 2d910d7dd32d70bcce8209ee88ead2f91445f3f4 From eb807682c7e4feba18aa43fba51eb8bedc3d2968 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Thu, 20 Nov 2025 11:24:54 +1100 Subject: [PATCH 14/26] Counting codepoints in utf-16 --- library/src/main/cpp/util.cpp | 10 ++++++++++ .../loki/messenger/libsession_util/util/Util.kt | 2 ++ libsession-util | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/library/src/main/cpp/util.cpp b/library/src/main/cpp/util.cpp index ed08fa0..87558b4 100644 --- a/library/src/main/cpp/util.cpp +++ b/library/src/main/cpp/util.cpp @@ -8,6 +8,8 @@ #include +#include + #define LOG_TAG "libsession_util" #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) @@ -337,4 +339,12 @@ Java_network_loki_messenger_libsession_1util_util_Util_lengthForCodepoints(JNIEn max_codepoints ); }); +} + +extern "C" +JNIEXPORT jint JNICALL +Java_network_loki_messenger_libsession_1util_util_Util_countCodepoints(JNIEnv *env, jobject thiz, + jstring str) { + jni_utils::JavaCharsRef str_ref(env, str); + return simdutf::count_utf16(reinterpret_cast(str_ref.chars()), str_ref.size()); } \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/util/Util.kt b/library/src/main/java/network/loki/messenger/libsession_util/util/Util.kt index 9d565ab..51485de 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/util/Util.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/util/Util.kt @@ -7,4 +7,6 @@ object Util : LibSessionUtilCApi() { fun truncateCodepoints(str: String, maxCodepoints: Int): String = str.take(lengthForCodepoints(str, maxCodepoints)) + + external fun countCodepoints(str: String): Int } \ No newline at end of file diff --git a/libsession-util b/libsession-util index 2d910d7..609bef6 160000 --- a/libsession-util +++ b/libsession-util @@ -1 +1 @@ -Subproject commit 2d910d7dd32d70bcce8209ee88ead2f91445f3f4 +Subproject commit 609bef6d7145fc2a17d552e6e987c00b9015b022 From a23afd05e3017c0d05d073479a380e1f23904d62 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Fri, 21 Nov 2025 09:10:16 +1100 Subject: [PATCH 15/26] Update libsession-util version --- library/src/main/cpp/util.cpp | 6 +++--- libsession-util | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/src/main/cpp/util.cpp b/library/src/main/cpp/util.cpp index 87558b4..a99440b 100644 --- a/library/src/main/cpp/util.cpp +++ b/library/src/main/cpp/util.cpp @@ -334,8 +334,8 @@ Java_network_loki_messenger_libsession_1util_util_Util_lengthForCodepoints(JNIEn jint max_codepoints) { return jni_utils::run_catching_cxx_exception_or_throws(env, [=]() { jni_utils::JavaCharsRef str_ref(env, str); - return session::utf16_len_for_codepoints( - { reinterpret_cast(str_ref.chars()), str_ref.size() }, + return session::utf16_count_truncated_to_codepoints( + {reinterpret_cast(str_ref.chars()), str_ref.size()}, max_codepoints ); }); @@ -346,5 +346,5 @@ JNIEXPORT jint JNICALL Java_network_loki_messenger_libsession_1util_util_Util_countCodepoints(JNIEnv *env, jobject thiz, jstring str) { jni_utils::JavaCharsRef str_ref(env, str); - return simdutf::count_utf16(reinterpret_cast(str_ref.chars()), str_ref.size()); + return session::utf16_count({reinterpret_cast(str_ref.chars()), str_ref.size()}); } \ No newline at end of file diff --git a/libsession-util b/libsession-util index 609bef6..0667fe6 160000 --- a/libsession-util +++ b/libsession-util @@ -1 +1 @@ -Subproject commit 609bef6d7145fc2a17d552e6e987c00b9015b022 +Subproject commit 0667fe6ccf0e8091b7917f43c74009653ca84113 From 611a7d13a2ff2c148bc76f85afe9e348e374def0 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Fri, 21 Nov 2025 16:03:31 +1100 Subject: [PATCH 16/26] Added integration for new properties in user config --- library/src/main/cpp/CMakeLists.txt | 2 +- library/src/main/cpp/pro_backend.cpp | 6 +- library/src/main/cpp/pro_proof.cpp | 51 --------- library/src/main/cpp/pro_proof_util.cpp | 94 ++++++++++++++++ library/src/main/cpp/pro_proof_util.h | 7 ++ library/src/main/cpp/protocol.cpp | 19 +--- library/src/main/cpp/user_profile.cpp | 106 +++++++++++++++++- .../loki/messenger/libsession_util/Config.kt | 23 ++-- .../messenger/libsession_util/UserProfile.kt | 26 +++++ .../libsession_util/pro/ProConfig.kt | 18 +++ .../messenger/libsession_util/pro/ProProof.kt | 24 +--- .../protocol/PaymentProviderMetadata.kt | 4 +- libsession-util | 2 +- 13 files changed, 278 insertions(+), 104 deletions(-) delete mode 100644 library/src/main/cpp/pro_proof.cpp create mode 100644 library/src/main/cpp/pro_proof_util.cpp create mode 100644 library/src/main/cpp/pro_proof_util.h create mode 100644 library/src/main/java/network/loki/messenger/libsession_util/pro/ProConfig.kt diff --git a/library/src/main/cpp/CMakeLists.txt b/library/src/main/cpp/CMakeLists.txt index ea96a21..f49bbfa 100644 --- a/library/src/main/cpp/CMakeLists.txt +++ b/library/src/main/cpp/CMakeLists.txt @@ -96,7 +96,7 @@ set(SOURCES webp_utils.cpp gif_utils.cpp pro_backend.cpp - pro_proof.cpp + pro_proof_util.cpp ${cgif_SOURCE_DIR}/src/cgif.c ${cgif_SOURCE_DIR}/src/cgif_rgb.c diff --git a/library/src/main/cpp/pro_backend.cpp b/library/src/main/cpp/pro_backend.cpp index e4127cc..d6014ef 100644 --- a/library/src/main/cpp/pro_backend.cpp +++ b/library/src/main/cpp/pro_backend.cpp @@ -76,14 +76,14 @@ Java_network_loki_messenger_libsession_1util_pro_BackendRequests_getPaymentProvi auto clazz = env->FindClass("network/loki/messenger/libsession_util/protocol/PaymentProviderMetadata"); return env->NewObject( clazz, - env->GetMethodID(clazz, "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"), + env->GetMethodID(clazz, "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"), util::jstringFromOptional(env, std::string_view(metadata.device.data, metadata.device.size)), util::jstringFromOptional(env, std::string_view(metadata.store.data, metadata.store.size)), util::jstringFromOptional(env, std::string_view(metadata.platform.data, metadata.platform.size)), util::jstringFromOptional(env, std::string_view(metadata.platform_account.data, metadata.platform_account.size)), - util::jstringFromOptional(env, std::string_view(metadata.refund_url.data, metadata.refund_url.size)), - util::jstringFromOptional(env, std::string_view(metadata.refund_after_platform_deadline_url.data, metadata.refund_after_platform_deadline_url.size)), + util::jstringFromOptional(env, std::string_view(metadata.refund_platform_url.data, metadata.refund_platform_url.size)), util::jstringFromOptional(env, std::string_view(metadata.refund_support_url.data, metadata.refund_support_url.size)), + util::jstringFromOptional(env, std::string_view(metadata.refund_status_url.data, metadata.refund_status_url.size)), util::jstringFromOptional(env, std::string_view(metadata.update_subscription_url.data, metadata.update_subscription_url.size)), util::jstringFromOptional(env, std::string_view(metadata.cancel_subscription_url.data, metadata.cancel_subscription_url.size)) ); diff --git a/library/src/main/cpp/pro_proof.cpp b/library/src/main/cpp/pro_proof.cpp deleted file mode 100644 index 7f90939..0000000 --- a/library/src/main/cpp/pro_proof.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include -#include -#include - -#include "util.h" -#include "jni_utils.h" - -using namespace jni_utils; - -extern "C" -JNIEXPORT jint JNICALL -Java_network_loki_messenger_libsession_1util_pro_ProProof_00024Companion_nativeStatus(JNIEnv *env, - jobject thiz, - jint version, - jbyteArray gen_index_hash, - jbyteArray rotating_pub_key, - jlong expiry_ms, - jbyteArray signature, - jlong now_unix_ts, - jbyteArray verify_pub_key, - jbyteArray signed_message_data, - jbyteArray signed_message_signature) { - return run_catching_cxx_exception_or_throws(env, [=]() { - std::optional signed_msg; - JavaByteArrayRef signed_message_data_ref(env, signed_message_data); - JavaByteArrayRef signed_message_signature_ref(env, signed_message_signature); - - if (signed_message_data && signed_message_signature) { - signed_msg.emplace(session::ProSignedMessage { - .sig = signed_message_signature_ref.get(), - .msg = signed_message_data_ref.get(), - }); - } - - session::ProProof pro_proof { - .version = static_cast(version), - .gen_index_hash = *java_to_cpp_array<32>(env, gen_index_hash), - .rotating_pubkey = *java_to_cpp_array<32>(env, rotating_pub_key), - .expiry_unix_ts = std::chrono::sys_time( - std::chrono::milliseconds(expiry_ms)), - .sig = *java_to_cpp_array<64>(env, signature), - }; - - return static_cast(pro_proof.status( - JavaByteArrayRef(env, verify_pub_key).get(), - std::chrono::sys_time{std::chrono::milliseconds(now_unix_ts)}, - signed_msg - )); - }); -} \ No newline at end of file diff --git a/library/src/main/cpp/pro_proof_util.cpp b/library/src/main/cpp/pro_proof_util.cpp new file mode 100644 index 0000000..2de5b7b --- /dev/null +++ b/library/src/main/cpp/pro_proof_util.cpp @@ -0,0 +1,94 @@ +#include +#include +#include +#include +#include + +#include "util.h" +#include "jni_utils.h" +#include "pro_proof_util.h" + +using namespace jni_utils; + +template +static std::array from_hex(std::span input) { + std::array output = {0}; + oxenc::from_hex(input.begin(), input.end(), output.begin()); + return output; +} + +session::ProProof java_to_cpp_proof(JNIEnv *env, jobject proof) { + struct ProProofMethods { + jmethodID get_version; + jmethodID get_gen_index_hash; + jmethodID get_rotating_pub_key; + jmethodID get_expiry_ms; + jmethodID get_signature; + + ProProofMethods(JNIEnv *env, jclass clazz) { + get_version = env->GetMethodID(clazz, "getVersion", "()I"); + get_gen_index_hash = env->GetMethodID(clazz, "getGenIndexHashHex", "()Ljava/lang/String;"); + get_rotating_pub_key = env->GetMethodID(clazz, "getRotatingPubKeyHex", "()Ljava/lang/String;"); + get_expiry_ms = env->GetMethodID(clazz, "getExpiryMs", "()J"); + get_signature = env->GetMethodID(clazz, "getSignatureHex", "()Ljava/lang/String;"); + } + }; + + // Cache method IDs + static ProProofMethods methods(env, jni_utils::JavaLocalRef(env, env->GetObjectClass(proof)).get()); + + jni_utils::JavaLocalRef gen_index_hash(env, (jstring) env->CallObjectMethod(proof, methods.get_gen_index_hash)); + jni_utils::JavaLocalRef rotating_pub_key(env, (jstring) env->CallObjectMethod(proof, methods.get_rotating_pub_key)); + jni_utils::JavaLocalRef signature(env, (jstring) env->CallObjectMethod(proof, methods.get_signature)); + + return { + .version = static_cast(env->CallIntMethod(proof, methods.get_version)), + .gen_index_hash = from_hex<32>(jni_utils::JavaStringRef(env, gen_index_hash.get()).get()), + .rotating_pubkey = from_hex<32>(jni_utils::JavaStringRef(env, rotating_pub_key.get()).get()), + .expiry_unix_ts = std::chrono::sys_time( + std::chrono::milliseconds(env->CallLongMethod(proof, methods.get_expiry_ms))), + .sig = from_hex<64>(jni_utils::JavaStringRef(env, signature.get()).get()), + }; +} + +jobject cpp_to_java_proof(JNIEnv *env, const session::ProProof &proof) { + JavaLocalRef pro_proof_clazz(env, env->FindClass( + "network/loki/messenger/libsession_util/pro/ProProof")); + jmethodID init = env->GetMethodID(pro_proof_clazz.get(), "", "(I[B[BJ[B)V"); + return env->NewObject( + pro_proof_clazz.get(), + init, + static_cast(proof.version), + util::bytes_from_span(env, proof.gen_index_hash), + util::bytes_from_span(env, proof.rotating_pubkey), + static_cast(proof.expiry_unix_ts.time_since_epoch().count()), + util::bytes_from_span(env, proof.sig) + ); +} + +extern "C" +JNIEXPORT jint JNICALL +Java_network_loki_messenger_libsession_1util_pro_ProProof_nativeStatus(JNIEnv *env, jobject thiz, + jlong now_unix_ts, + jbyteArray verify_pub_key, + jbyteArray signed_message_data, + jbyteArray signed_message_signature) { + return run_catching_cxx_exception_or_throws(env, [=]() { + std::optional signed_msg; + JavaByteArrayRef signed_message_data_ref(env, signed_message_data); + JavaByteArrayRef signed_message_signature_ref(env, signed_message_signature); + + if (signed_message_data && signed_message_signature) { + signed_msg.emplace(session::ProSignedMessage { + .sig = signed_message_signature_ref.get(), + .msg = signed_message_data_ref.get(), + }); + } + + return static_cast(java_to_cpp_proof(env, thiz).status( + JavaByteArrayRef(env, verify_pub_key).get(), + std::chrono::sys_time{std::chrono::milliseconds(now_unix_ts)}, + signed_msg + )); + }); +} \ No newline at end of file diff --git a/library/src/main/cpp/pro_proof_util.h b/library/src/main/cpp/pro_proof_util.h new file mode 100644 index 0000000..d103fc8 --- /dev/null +++ b/library/src/main/cpp/pro_proof_util.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include + +session::ProProof java_to_cpp_proof(JNIEnv *, jobject proof); +jobject cpp_to_java_proof(JNIEnv *, const session::ProProof &proof); \ No newline at end of file diff --git a/library/src/main/cpp/protocol.cpp b/library/src/main/cpp/protocol.cpp index 3eb7729..c35a7d7 100644 --- a/library/src/main/cpp/protocol.cpp +++ b/library/src/main/cpp/protocol.cpp @@ -3,24 +3,11 @@ #include #include "jni_utils.h" +#include "pro_proof_util.h" using namespace jni_utils; -static JavaLocalRef serializeProProof(JNIEnv *env, const session::ProProof &proof) { - JavaLocalRef pro_proof_clazz(env, env->FindClass( - "network/loki/messenger/libsession_util/pro/ProProof")); - jmethodID init = env->GetMethodID(pro_proof_clazz.get(), "", "(I[B[BJ[B)V"); - return {env, env->NewObject( - pro_proof_clazz.get(), - init, - static_cast(proof.version), - util::bytes_from_span(env, proof.gen_index_hash), - util::bytes_from_span(env, proof.rotating_pubkey), - static_cast(proof.expiry_unix_ts.time_since_epoch().count()), - util::bytes_from_span(env, proof.sig) - )}; -} static JavaLocalRef serializeEnvelop(JNIEnv *env, const session::Envelope &envelope) { JavaLocalRef envelopClass(env, env->FindClass( @@ -60,7 +47,7 @@ static jobject serializeDecodedEnvelope(JNIEnv *env, const session::DecodedEnvel serializeEnvelop(env, envelop.envelope).get(), envelop.pro ? static_cast(envelop.pro->status) : static_cast(-1), - envelop.pro ? serializeProProof(env, envelop.pro->proof).get() : nullptr, + envelop.pro ? JavaLocalRef(env, cpp_to_java_proof(env, envelop.pro->proof)).get() : nullptr, static_cast(envelop.pro ? envelop.pro->features : 0), content.get(), sender_ed25519.get(), @@ -174,7 +161,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeForC init, decoded.pro ? static_cast(decoded.pro->status) : static_cast(-1), - decoded.pro ? serializeProProof(env, decoded.pro->proof).get() : nullptr, + decoded.pro ? JavaLocalRef(env, cpp_to_java_proof(env, decoded.pro->proof)).get() : nullptr, static_cast(decoded.pro ? decoded.pro->features : 0), util::bytes_from_vector(env, decoded.content_plaintext) ); diff --git a/library/src/main/cpp/user_profile.cpp b/library/src/main/cpp/user_profile.cpp index 37ee92a..9751180 100644 --- a/library/src/main/cpp/user_profile.cpp +++ b/library/src/main/cpp/user_profile.cpp @@ -1,10 +1,11 @@ #include "user_profile.h" #include "util.h" +#include "pro_proof_util.h" extern "C" { JNIEXPORT void JNICALL Java_network_loki_messenger_libsession_1util_UserProfile_setName( - JNIEnv* env, + JNIEnv *env, jobject thiz, jstring newName) { auto profile = ptrToProfile(env, thiz); @@ -57,7 +58,7 @@ Java_network_loki_messenger_libsession_1util_UserProfile_setNtsExpiry(JNIEnv *en jobject expiry_mode) { auto profile = ptrToProfile(env, thiz); auto expiry = util::deserialize_expiry(env, expiry_mode); - profile->set_nts_expiry(std::chrono::seconds (expiry.second)); + profile->set_nts_expiry(std::chrono::seconds(expiry.second)); } extern "C" @@ -66,10 +67,12 @@ Java_network_loki_messenger_libsession_1util_UserProfile_getNtsExpiry(JNIEnv *en auto profile = ptrToProfile(env, thiz); auto nts_expiry = profile->get_nts_expiry(); if (nts_expiry == std::nullopt) { - auto expiry = util::serialize_expiry(env, session::config::expiration_mode::none, std::chrono::seconds(0)); + auto expiry = util::serialize_expiry(env, session::config::expiration_mode::none, + std::chrono::seconds(0)); return expiry; } - auto expiry = util::serialize_expiry(env, session::config::expiration_mode::after_send, std::chrono::seconds(*nts_expiry)); + auto expiry = util::serialize_expiry(env, session::config::expiration_mode::after_send, + std::chrono::seconds(*nts_expiry)); return expiry; } @@ -90,7 +93,7 @@ JNIEXPORT void JNICALL Java_network_loki_messenger_libsession_1util_UserProfile_setCommunityMessageRequests( JNIEnv *env, jobject thiz, jboolean blocks) { auto profile = ptrToProfile(env, thiz); - profile->set_blinded_msgreqs(std::optional{(bool)blocks}); + profile->set_blinded_msgreqs(std::optional{(bool) blocks}); } extern "C" @@ -113,4 +116,97 @@ JNIEXPORT void JNICALL Java_network_loki_messenger_libsession_1util_UserProfile_setReuploadedPic(JNIEnv *env, jobject thiz, jobject user_pic) { ptrToProfile(env, thiz)->set_reupload_profile_pic(util::deserialize_user_pic(env, user_pic)); +} + +extern "C" +JNIEXPORT void JNICALL +Java_network_loki_messenger_libsession_1util_UserProfile_removeProConfig(JNIEnv *env, + jobject thiz) { + ptrToProfile(env, thiz)->remove_pro_config(); +} + +extern "C" +JNIEXPORT void JNICALL +Java_network_loki_messenger_libsession_1util_UserProfile_setProConfig(JNIEnv *env, jobject thiz, + jobject proof, + jbyteArray rotating_private_key) { + jni_utils::run_catching_cxx_exception_or_throws(env, [=]() { + + jni_utils::JavaByteArrayRef key_ref(env, rotating_private_key); + auto r = key_ref.get(); + session::cleared_uc64 rotating_privkey; + std::copy(r.begin(), r.end(), rotating_privkey.begin()); + + ptrToProfile(env, thiz)->set_pro_config( + { + .rotating_privkey = rotating_privkey, + .proof = java_to_cpp_proof(env, proof), + } + ); + }); +} + +extern "C" +JNIEXPORT void JNICALL +Java_network_loki_messenger_libsession_1util_UserProfile_setProBadge(JNIEnv *env, jobject thiz, + jboolean pro_badge) { + ptrToProfile(env, thiz)->set_pro_badge(pro_badge); +} + +extern "C" +JNIEXPORT void JNICALL +Java_network_loki_messenger_libsession_1util_UserProfile_setAnimatedAvatar(JNIEnv *env, + jobject thiz, + jboolean enabled) { + ptrToProfile(env, thiz)->set_animated_avatar(enabled); +} + +extern "C" +JNIEXPORT void JNICALL +Java_network_loki_messenger_libsession_1util_UserProfile_setProAccessExpiryMs(JNIEnv *env, + jobject thiz, + jlong epoch_mills) { + ptrToProfile(env, thiz)->set_pro_access_expiry(std::chrono::sys_time{ + std::chrono::milliseconds{epoch_mills} + }); +} + +extern "C" +JNIEXPORT void JNICALL +Java_network_loki_messenger_libsession_1util_UserProfile_removeProAccessExpiry(JNIEnv *env, + jobject thiz) { + ptrToProfile(env, thiz)->set_pro_access_expiry(std::nullopt); +} + +extern "C" +JNIEXPORT jlong JNICALL +Java_network_loki_messenger_libsession_1util_UserProfile_getProFeaturesRaw(JNIEnv *env, + jobject thiz) { + return static_cast(ptrToProfile(env, thiz)->get_pro_features()); +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_network_loki_messenger_libsession_1util_UserProfile_getProConfig(JNIEnv *env, jobject thiz) { + auto profile = ptrToProfile(env, thiz)->get_pro_config(); + if (profile) { + return nullptr; + } + + auto clazz = env->FindClass("network/loki/messenger/libsession_util/pro/ProConfig"); + auto constructor = env->GetMethodID(clazz, "", "(Lnetwork/loki/messenger/libsession_util/pro/ProProof;[B)V"); + + return env->NewObject(clazz, + constructor, + cpp_to_java_proof(env, profile->proof), + util::bytes_from_span(env, profile->rotating_privkey) + ); +} + +extern "C" +JNIEXPORT jlong JNICALL +Java_network_loki_messenger_libsession_1util_UserProfile_getProAccessExpiryMsOrZero(JNIEnv *env, + jobject thiz) { + auto expiry = ptrToProfile(env, thiz)->get_pro_access_expiry(); + return expiry ? expiry->time_since_epoch().count() : 0; } \ No newline at end of file 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 3c8d058..c509457 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 @@ -1,5 +1,7 @@ package network.loki.messenger.libsession_util +import network.loki.messenger.libsession_util.pro.ProConfig +import network.loki.messenger.libsession_util.protocol.ProFeatures import network.loki.messenger.libsession_util.util.BaseCommunityInfo import network.loki.messenger.libsession_util.util.BlindedContact import network.loki.messenger.libsession_util.util.ConfigPush @@ -9,9 +11,8 @@ import network.loki.messenger.libsession_util.util.ExpiryMode import network.loki.messenger.libsession_util.util.GroupInfo import network.loki.messenger.libsession_util.util.GroupMember import network.loki.messenger.libsession_util.util.UserPic -import java.io.Closeable -sealed class Config(initialPointer: Long): Closeable, LibSessionUtilCApi() { +sealed class Config(initialPointer: Long): LibSessionUtilCApi() { var pointer = initialPointer private set @@ -23,11 +24,8 @@ sealed class Config(initialPointer: Long): Closeable, LibSessionUtilCApi() { private external fun free() - final override fun close() { - if (pointer != 0L) { - free() - pointer = 0L - } + protected fun finalize() { + free() } } @@ -78,6 +76,10 @@ interface ReadableUserProfile: ReadableConfig { fun getNtsExpiry(): ExpiryMode fun getCommunityMessageRequests(): Boolean fun isBlockCommunityMessageRequestsSet(): Boolean + + fun getProFeatures(): ProFeatures + fun getProConfig(): ProConfig? + fun getProAccessExpiryMs(): Long? } interface MutableUserProfile : ReadableUserProfile, MutableConfig { @@ -95,6 +97,13 @@ interface MutableUserProfile : ReadableUserProfile, MutableConfig { fun setNtsPriority(priority: Long) fun setNtsExpiry(expiryMode: ExpiryMode) fun setCommunityMessageRequests(blocks: Boolean) + + fun removeProConfig() + fun setProConfig(proConfig: ProConfig) + fun setProBadge(proBadge: Boolean) + fun setAnimatedAvatar(animatedAvatar: Boolean) + fun setProAccessExpiryMs(epochMills: Long) + fun removeProAccessExpiry() } interface ReadableConversationVolatileConfig: ReadableConfig { diff --git a/library/src/main/java/network/loki/messenger/libsession_util/UserProfile.kt b/library/src/main/java/network/loki/messenger/libsession_util/UserProfile.kt index b1170b3..4c313c6 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/UserProfile.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/UserProfile.kt @@ -1,5 +1,8 @@ package network.loki.messenger.libsession_util +import network.loki.messenger.libsession_util.pro.ProConfig +import network.loki.messenger.libsession_util.pro.ProProof +import network.loki.messenger.libsession_util.protocol.ProFeatures import network.loki.messenger.libsession_util.util.ExpiryMode import network.loki.messenger.libsession_util.util.UserPic @@ -27,4 +30,27 @@ class UserProfile private constructor(pointer: Long) : ConfigBase(pointer), Muta external override fun getCommunityMessageRequests(): Boolean external override fun setCommunityMessageRequests(blocks: Boolean) external override fun isBlockCommunityMessageRequestsSet(): Boolean + + external override fun removeProConfig() + + private external fun setProConfig( + proof: ProProof, + rotatingPrivateKey: ByteArray + ) + + override fun setProConfig(proConfig: ProConfig) = setProConfig( + proConfig.proProof, + proConfig.rotatingPrivateKey.data + ) + + external override fun setProBadge(proBadge: Boolean) + external override fun setAnimatedAvatar(animatedAvatar: Boolean) + external override fun setProAccessExpiryMs(epochMills: Long) + external override fun removeProAccessExpiry() + private external fun getProFeaturesRaw(): Long + override fun getProFeatures(): ProFeatures = ProFeatures(getProFeaturesRaw()) + external override fun getProConfig(): ProConfig? + + private external fun getProAccessExpiryMsOrZero(): Long + override fun getProAccessExpiryMs(): Long? = getProAccessExpiryMsOrZero().takeIf { it != 0L } } \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/ProConfig.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/ProConfig.kt new file mode 100644 index 0000000..959bd5c --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/pro/ProConfig.kt @@ -0,0 +1,18 @@ +package network.loki.messenger.libsession_util.pro + +import androidx.annotation.Keep +import network.loki.messenger.libsession_util.util.Bytes + +data class ProConfig( + val proProof: ProProof, + val rotatingPrivateKey: Bytes +) { + @Keep + constructor( + proProof: ProProof, + rotatingPrivateKey: ByteArray + ) : this( + proProof, + Bytes(rotatingPrivateKey) + ) +} diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt index 1c9d1e7..e4da110 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt @@ -89,11 +89,6 @@ data class ProProof( val signedMessageData = signedMessage?.data val signedMessageSignature = signedMessage?.signature val statusValue = nativeStatus( - version = version, - genIndexHash = genIndexHashHex.hexToByteArray(), - rotatingPubKey = rotatingPubKeyHex.hexToByteArray(), - expiryMs = expiryMs, - signature = signatureHex.hexToByteArray(), nowUnixTs = now.toEpochMilli(), verifyPubKey = senderED25519PubKey, signedMessageData = signedMessageData, @@ -103,17 +98,10 @@ data class ProProof( return Status.fromNativeValue(statusValue) } - companion object { - private external fun nativeStatus( - version: Int, - genIndexHash: ByteArray, - rotatingPubKey: ByteArray, - expiryMs: Long, - signature: ByteArray, - nowUnixTs: Long, - verifyPubKey: ByteArray, - signedMessageData: ByteArray?, - signedMessageSignature: ByteArray? - ): Int - } + private external fun nativeStatus( + nowUnixTs: Long, + verifyPubKey: ByteArray, + signedMessageData: ByteArray?, + signedMessageSignature: ByteArray? + ): Int } \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/PaymentProviderMetadata.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/PaymentProviderMetadata.kt index 0a9a32e..c7b7149 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/protocol/PaymentProviderMetadata.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/PaymentProviderMetadata.kt @@ -7,9 +7,9 @@ data class PaymentProviderMetadata @Keep constructor( val store: String, val platform: String, val platformAccount: String, - val refundUrl: String, - val refundAfterPlatformDeadlineUrl: String, + val refundPlatformUrl: String, val refundSupportUrl: String, + val refundStatusUrl: String, val updateSubscriptionUrl: String, val cancelSubscriptionUrl: String, ) \ No newline at end of file diff --git a/libsession-util b/libsession-util index 0667fe6..3731a9f 160000 --- a/libsession-util +++ b/libsession-util @@ -1 +1 @@ -Subproject commit 0667fe6ccf0e8091b7917f43c74009653ca84113 +Subproject commit 3731a9f90fb6be5e98a970ad8a2956c8fcb2e68c From c9fece440b0ea76a934bc5c95e7d9e7da092fed8 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Fri, 21 Nov 2025 16:13:06 +1100 Subject: [PATCH 17/26] Tidy up --- library/src/main/cpp/config_base.cpp | 28 ------------------- .../loki/messenger/libsession_util/Config.kt | 10 +++++-- .../messenger/libsession_util/ConfigBase.kt | 12 -------- .../libsession_util/util/BlindedContact.kt | 4 ++- .../messenger/libsession_util/util/Contact.kt | 5 +++- 5 files changed, 15 insertions(+), 44 deletions(-) diff --git a/library/src/main/cpp/config_base.cpp b/library/src/main/cpp/config_base.cpp index ae23c72..fd85bc4 100644 --- a/library/src/main/cpp/config_base.cpp +++ b/library/src/main/cpp/config_base.cpp @@ -96,34 +96,6 @@ Java_network_loki_messenger_libsession_1util_ConfigBase_merge___3Lkotlin_Pair_2( #pragma clang diagnostic pop } -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 -Java_network_loki_messenger_libsession_1util_ConfigBase_00024Companion_kindFor(JNIEnv *env, - jobject thiz, - jint config_namespace) { - auto user_class = env->FindClass("network/loki/messenger/libsession_util/UserProfile"); - auto contact_class = env->FindClass("network/loki/messenger/libsession_util/Contacts"); - auto convo_volatile_class = env->FindClass("network/loki/messenger/libsession_util/ConversationVolatileConfig"); - auto group_list_class = env->FindClass("network/loki/messenger/libsession_util/UserGroupsConfig"); - switch (config_namespace) { - case (int)session::config::Namespace::UserProfile: - return user_class; - case (int)session::config::Namespace::Contacts: - return contact_class; - case (int)session::config::Namespace::ConvoInfoVolatile: - return convo_volatile_class; - case (int)session::config::Namespace::UserGroups: - return group_list_class; - default: - return nullptr; - } -} extern "C" JNIEXPORT jobject JNICALL 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 c509457..57dc19c 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 @@ -12,6 +12,12 @@ import network.loki.messenger.libsession_util.util.GroupInfo import network.loki.messenger.libsession_util.util.GroupMember import network.loki.messenger.libsession_util.util.UserPic +typealias ConversationPriority = Long + +const val PRIORITY_HIDDEN: ConversationPriority = -1L +const val PRIORITY_VISIBLE: ConversationPriority = 0L +const val PRIORITY_PINNED: ConversationPriority = 1L + sealed class Config(initialPointer: Long): LibSessionUtilCApi() { var pointer = initialPointer private set @@ -72,7 +78,7 @@ interface ReadableUserProfile: ReadableConfig { fun getName(): String? fun getPic(): UserPic fun getProfileUpdatedSeconds(): Long - fun getNtsPriority(): Long + fun getNtsPriority(): ConversationPriority fun getNtsExpiry(): ExpiryMode fun getCommunityMessageRequests(): Boolean fun isBlockCommunityMessageRequestsSet(): Boolean @@ -94,7 +100,7 @@ interface MutableUserProfile : ReadableUserProfile, MutableConfig { * Called when setting a re-uploaded pic */ fun setReuploadedPic(userPic: UserPic) - fun setNtsPriority(priority: Long) + fun setNtsPriority(priority: ConversationPriority) fun setNtsExpiry(expiryMode: ExpiryMode) fun setCommunityMessageRequests(blocks: Boolean) diff --git a/library/src/main/java/network/loki/messenger/libsession_util/ConfigBase.kt b/library/src/main/java/network/loki/messenger/libsession_util/ConfigBase.kt index f0c8bc0..b914598 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/ConfigBase.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/ConfigBase.kt @@ -3,18 +3,6 @@ package network.loki.messenger.libsession_util import network.loki.messenger.libsession_util.util.ConfigPush sealed class ConfigBase(pointer: Long): Config(pointer), MutableConfig { - companion object { - init { - System.loadLibrary("session_util") - } - external fun kindFor(configNamespace: Int): Class - - const val PRIORITY_HIDDEN = -1L - const val PRIORITY_VISIBLE = 0L - const val PRIORITY_PINNED = 1L - - } - external override fun dirty(): Boolean external override fun needsPush(): Boolean external override fun needsDump(): Boolean diff --git a/library/src/main/java/network/loki/messenger/libsession_util/util/BlindedContact.kt b/library/src/main/java/network/loki/messenger/libsession_util/util/BlindedContact.kt index d725200..aa619c1 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/util/BlindedContact.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/util/BlindedContact.kt @@ -1,5 +1,7 @@ package network.loki.messenger.libsession_util.util +import network.loki.messenger.libsession_util.ConversationPriority + data class BlindedContact( val id: String, val communityServer: String, @@ -8,7 +10,7 @@ data class BlindedContact( var createdEpochSeconds: Long, var profileUpdatedEpochSeconds: Long, var profilePic: UserPic, - var priority: Long, + var priority: ConversationPriority, ) { @OptIn(ExperimentalStdlibApi::class) val communityServerPubKey: ByteArray diff --git a/library/src/main/java/network/loki/messenger/libsession_util/util/Contact.kt b/library/src/main/java/network/loki/messenger/libsession_util/util/Contact.kt index 1816c05..61f1bf5 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/util/Contact.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/util/Contact.kt @@ -1,5 +1,8 @@ package network.loki.messenger.libsession_util.util +import network.loki.messenger.libsession_util.ConversationPriority +import network.loki.messenger.libsession_util.PRIORITY_VISIBLE + data class Contact( val id: String, var name: String = "", @@ -10,7 +13,7 @@ data class Contact( var profilePicture: UserPic = UserPic.DEFAULT, var createdEpochSeconds: Long = 0, var profileUpdatedEpochSeconds: Long = 0, - var priority: Long = 0, + var priority: ConversationPriority = PRIORITY_VISIBLE, var expiryMode: ExpiryMode = ExpiryMode.NONE, ) { val displayName: String From dc4302a97b8c77dcc49531c0e6fc9f5d6ecb8d46 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Fri, 21 Nov 2025 17:06:59 +1100 Subject: [PATCH 18/26] Fixed crash on payment provider meta --- gradle/libs.versions.toml | 2 +- library/src/main/cpp/pro_backend.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f1f8436..5912915 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agp = "8.13.1" -kotlin = "2.2.20" +kotlin = "2.2.21" [libraries] junit = { module = "junit:junit", version = "4.13.2" } diff --git a/library/src/main/cpp/pro_backend.cpp b/library/src/main/cpp/pro_backend.cpp index d6014ef..54f3561 100644 --- a/library/src/main/cpp/pro_backend.cpp +++ b/library/src/main/cpp/pro_backend.cpp @@ -76,7 +76,7 @@ Java_network_loki_messenger_libsession_1util_pro_BackendRequests_getPaymentProvi auto clazz = env->FindClass("network/loki/messenger/libsession_util/protocol/PaymentProviderMetadata"); return env->NewObject( clazz, - env->GetMethodID(clazz, "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"), + env->GetMethodID(clazz, "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"), util::jstringFromOptional(env, std::string_view(metadata.device.data, metadata.device.size)), util::jstringFromOptional(env, std::string_view(metadata.store.data, metadata.store.size)), util::jstringFromOptional(env, std::string_view(metadata.platform.data, metadata.platform.size)), From de0502d8fa5955560720decc87f287bd26c5ca10 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Fri, 21 Nov 2025 17:16:03 +1100 Subject: [PATCH 19/26] Fix crash --- library/src/main/cpp/user_profile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/cpp/user_profile.cpp b/library/src/main/cpp/user_profile.cpp index 9751180..e7f15ee 100644 --- a/library/src/main/cpp/user_profile.cpp +++ b/library/src/main/cpp/user_profile.cpp @@ -189,7 +189,7 @@ extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_UserProfile_getProConfig(JNIEnv *env, jobject thiz) { auto profile = ptrToProfile(env, thiz)->get_pro_config(); - if (profile) { + if (!profile) { return nullptr; } From ac654a0a403b1412576c578182ea39efab0d3193 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Mon, 24 Nov 2025 15:09:48 +1100 Subject: [PATCH 20/26] Refactor a few C layer reflection access --- library/src/main/cpp/attachments.cpp | 3 +- library/src/main/cpp/blinded_key.cpp | 14 +- library/src/main/cpp/config_base.cpp | 17 +- library/src/main/cpp/config_base.h | 12 - library/src/main/cpp/contacts.cpp | 234 +++++++------ library/src/main/cpp/contacts.h | 4 +- library/src/main/cpp/conversation.cpp | 314 ++++++++++++------ library/src/main/cpp/curve25519.cpp | 9 +- library/src/main/cpp/ed25519.cpp | 9 +- library/src/main/cpp/encryption.cpp | 19 +- library/src/main/cpp/group_info.cpp | 15 +- library/src/main/cpp/group_keys.cpp | 47 +-- library/src/main/cpp/group_members.cpp | 41 ++- library/src/main/cpp/group_members.h | 1 + library/src/main/cpp/jni_utils.cpp | 26 +- library/src/main/cpp/jni_utils.h | 80 ++++- library/src/main/cpp/pro_backend.cpp | 24 +- library/src/main/cpp/pro_proof_util.cpp | 6 +- library/src/main/cpp/protocol.cpp | 55 ++- library/src/main/cpp/user_groups.cpp | 264 +++++++++++++-- library/src/main/cpp/user_groups.h | 173 +--------- library/src/main/cpp/user_profile.cpp | 14 +- library/src/main/cpp/util.cpp | 93 ++---- library/src/main/cpp/util.h | 19 +- .../loki/messenger/libsession_util/Config.kt | 6 + .../ConversationVolatileConfig.kt | 3 + .../libsession_util/util/Conversation.kt | 50 ++- 27 files changed, 893 insertions(+), 659 deletions(-) diff --git a/library/src/main/cpp/attachments.cpp b/library/src/main/cpp/attachments.cpp index 109c256..0a7a598 100644 --- a/library/src/main/cpp/attachments.cpp +++ b/library/src/main/cpp/attachments.cpp @@ -1,6 +1,7 @@ #include #include #include "jni_utils.h" +#include "util.h" using namespace session::attachment; using namespace jni_utils; @@ -49,7 +50,7 @@ Java_network_loki_messenger_libsession_1util_encrypt_Attachments_encryptBytes(JN ); - return util::bytes_from_span(env, std::span(reinterpret_cast(key.data()), key.size())); + return util::bytes_from_span(env, std::span(reinterpret_cast(key.data()), key.size())).leak(); }); } diff --git a/library/src/main/cpp/blinded_key.cpp b/library/src/main/cpp/blinded_key.cpp index 28ccd77..4412663 100644 --- a/library/src/main/cpp/blinded_key.cpp +++ b/library/src/main/cpp/blinded_key.cpp @@ -17,7 +17,7 @@ Java_network_loki_messenger_libsession_1util_util_BlindKeyAPI_blindVersionKeyPai jbyteArray ed25519_secret_key) { return jni_utils::run_catching_cxx_exception_or_throws(env, [=] { const auto [pk, sk] = session::blind_version_key_pair(util::vector_from_bytes(env, ed25519_secret_key)); - return jni_utils::new_key_pair(env, util::bytes_from_span(env, pk), util::bytes_from_span(env, sk)); + return jni_utils::new_key_pair(env, util::bytes_from_span(env, pk).get(), util::bytes_from_span(env, sk).get()); }); } extern "C" @@ -32,7 +32,7 @@ Java_network_loki_messenger_libsession_1util_util_BlindKeyAPI_blindVersionSign(J session::Platform::android, timestamp ); - return util::bytes_from_vector(env, bytes); + return util::bytes_from_vector(env, bytes).leak(); }); } @@ -53,7 +53,7 @@ Java_network_loki_messenger_libsession_1util_util_BlindKeyAPI_blindVersionSignRe jni_utils::JavaStringRef(env, path).view(), body ? std::make_optional(jni_utils::JavaByteArrayRef(env, body).get()) : std::nullopt ); - return util::bytes_from_vector(env, bytes); + return util::bytes_from_vector(env, bytes).leak(); }); } @@ -68,7 +68,7 @@ Java_network_loki_messenger_libsession_1util_util_BlindKeyAPI_blind15KeyPair(JNI jni_utils::JavaByteArrayRef(env, ed25519_secret_key).get(), jni_utils::JavaByteArrayRef(env, server_pub_key).get() ); - return jni_utils::new_key_pair(env, util::bytes_from_span(env, pk), util::bytes_from_span(env, sk)); + return jni_utils::new_key_pair(env, util::bytes_from_span(env, pk).get(), util::bytes_from_span(env, sk).get()); }); } @@ -84,7 +84,7 @@ Java_network_loki_messenger_libsession_1util_util_BlindKeyAPI_blind15Sign(JNIEnv jni_utils::JavaStringRef(env, server_pub_key).view(), jni_utils::JavaByteArrayRef(env, message).get() ); - return util::bytes_from_vector(env, data); + return util::bytes_from_vector(env, data).leak(); }); } @@ -128,9 +128,9 @@ Java_network_loki_messenger_libsession_1util_util_BlindKeyAPI_blind25Id(JNIEnv * jstring session_id, jstring server_pub_key) { return jni_utils::run_catching_cxx_exception_or_throws(env, [=]() -> jstring { - return util::jstringFromOptional(env, session::blind25_id( + return jni_utils::jstring_from_optional(env, session::blind25_id( jni_utils::JavaStringRef(env, session_id).view(), jni_utils::JavaStringRef(env, server_pub_key).view() - )); + )).leak(); }); } \ No newline at end of file diff --git a/library/src/main/cpp/config_base.cpp b/library/src/main/cpp/config_base.cpp index fd85bc4..013eb06 100644 --- a/library/src/main/cpp/config_base.cpp +++ b/library/src/main/cpp/config_base.cpp @@ -2,6 +2,20 @@ #include "util.h" #include "jni_utils.h" + +std::pair> extractHashAndData(JNIEnv *env, jobject kotlin_pair) { + jni_utils::JavaLocalRef pair(env, env->GetObjectClass(kotlin_pair)); + jfieldID first = env->GetFieldID(pair.get(), "first", "Ljava/lang/Object;"); + jfieldID second = env->GetFieldID(pair.get(), "second", "Ljava/lang/Object;"); + auto hash_as_jstring = jni_utils::JavaLocalRef(env, reinterpret_cast(env->GetObjectField(kotlin_pair, first))); + auto data_as_jbytes = jni_utils::JavaLocalRef(env, reinterpret_cast(env->GetObjectField(kotlin_pair, second))); + + return std::make_pair( + std::string(jni_utils::JavaStringRef(env, hash_as_jstring.get()).view()), + jni_utils::JavaByteArrayRef(env, data_as_jbytes.get()).copy() + ); +} + extern "C" { JNIEXPORT jboolean JNICALL Java_network_loki_messenger_libsession_1util_ConfigBase_dirty(JNIEnv *env, jobject thiz) { @@ -49,8 +63,7 @@ JNIEXPORT jbyteArray JNICALL Java_network_loki_messenger_libsession_1util_ConfigBase_dump(JNIEnv *env, jobject thiz) { auto config = ptrToConfigBase(env, thiz); auto dumped = config->dump(); - jbyteArray bytes = util::bytes_from_vector(env, dumped); - return bytes; + return util::bytes_from_vector(env, dumped).leak(); } JNIEXPORT jstring JNICALL diff --git a/library/src/main/cpp/config_base.h b/library/src/main/cpp/config_base.h index 5eebd45..d42353c 100644 --- a/library/src/main/cpp/config_base.h +++ b/library/src/main/cpp/config_base.h @@ -14,18 +14,6 @@ inline session::config::ConfigBase* ptrToConfigBase(JNIEnv *env, jobject obj) { return (session::config::ConfigBase*) env->GetLongField(obj, pointerField); } -inline std::pair> extractHashAndData(JNIEnv *env, jobject kotlin_pair) { - auto pair = jni_utils::JavaLocalRef(env, env->FindClass("kotlin/Pair")); - jfieldID first = env->GetFieldID(pair.get(), "first", "Ljava/lang/Object;"); - jfieldID second = env->GetFieldID(pair.get(), "second", "Ljava/lang/Object;"); - auto hash_as_jstring = jni_utils::JavaLocalRef(env, reinterpret_cast(env->GetObjectField(kotlin_pair, first))); - auto data_as_jbytes = jni_utils::JavaLocalRef(env, reinterpret_cast(env->GetObjectField(kotlin_pair, second))); - - return std::make_pair( - std::string(jni_utils::JavaStringRef(env, hash_as_jstring.get()).view()), - jni_utils::JavaByteArrayRef(env, data_as_jbytes.get()).copy() - ); -} inline session::config::ConfigSig* ptrToConfigSig(JNIEnv* env, jobject obj) { auto sigClass = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/ConfigSig")); diff --git a/library/src/main/cpp/contacts.cpp b/library/src/main/cpp/contacts.cpp index 51d504d..1d5eb46 100644 --- a/library/src/main/cpp/contacts.cpp +++ b/library/src/main/cpp/contacts.cpp @@ -2,26 +2,109 @@ #include "util.h" #include "jni_utils.h" -session::config::Contacts *ptrToContacts(JNIEnv *env, jobject obj) { - auto contactsClass = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/Contacts")); +using namespace jni_utils; + +static session::config::Contacts *ptrToContacts(JNIEnv *env, jobject obj) { + auto contactsClass = JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/Contacts")); jfieldID pointerField = env->GetFieldID(contactsClass.get(), "pointer", "J"); return (session::config::Contacts *) env->GetLongField(obj, pointerField); } +static JavaLocalRef serialize_contact(JNIEnv *env, session::config::contact_info info) { + static BasicJavaClassInfo class_info( + env, "network/loki/messenger/libsession_util/util/Contact", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZLnetwork/loki/messenger/libsession_util/util/UserPic;JJJLnetwork/loki/messenger/libsession_util/util/ExpiryMode;)V"); + + jobject returnObj = env->NewObject(class_info.java_class, + class_info.constructor, + JavaLocalRef(env, env->NewStringUTF(info.session_id.data())).get(), + JavaLocalRef(env, env->NewStringUTF(info.name.data())).get(), + JavaLocalRef(env, env->NewStringUTF(info.nickname.data())).get(), + (jboolean) info.approved, + (jboolean) info.approved_me, + (jboolean) info.blocked, + util::serialize_user_pic(env, info.profile_picture).get(), + (jlong) info.created, + (jlong) (info.profile_updated.time_since_epoch().count()), + (jlong) info.priority, + util::serialize_expiry(env, info.exp_mode, info.exp_timer).get()); + return {env, returnObj}; +} + +session::config::contact_info deserialize_contact(JNIEnv *env, jobject info, session::config::Contacts *conf) { + struct ClassInfo { + jclass java_class; + jmethodID get_id; + jmethodID get_name; + jmethodID get_nick; + jmethodID get_approved; + jmethodID get_approved_me; + jmethodID get_blocked; + jmethodID get_user_pic; + jmethodID get_priority; + jmethodID get_expiry; + jmethodID get_profile_updated; + + ClassInfo(JNIEnv *env, jclass clazz): + java_class((jclass) env->NewGlobalRef(clazz)), + get_id(env->GetMethodID(clazz, "getId", "()Ljava/lang/String;")), + get_name(env->GetMethodID(clazz, "getName", "()Ljava/lang/String;")), + get_nick(env->GetMethodID(clazz, "getNickname", "()Ljava/lang/String;")), + get_approved(env->GetMethodID(clazz, "getApproved", "()Z")), + get_approved_me(env->GetMethodID(clazz, "getApprovedMe", "()Z")), + get_blocked(env->GetMethodID(clazz, "getBlocked", "()Z")), + get_user_pic(env->GetMethodID(clazz, "getProfilePicture", "()Lnetwork/loki/messenger/libsession_util/util/UserPic;")), + get_priority(env->GetMethodID(clazz, "getPriority", "()J")), + get_expiry(env->GetMethodID(clazz, "getExpiryMode", "()Lnetwork/loki/messenger/libsession_util/util/ExpiryMode;")), + get_profile_updated(env->GetMethodID(clazz, "getProfileUpdatedEpochSeconds", "()J")) {} + }; + + static ClassInfo class_info(env, JavaLocalRef(env, env->GetObjectClass(info)).get()); + + JavaLocalRef account_id(env, static_cast(env->CallObjectMethod(info, class_info.get_id))); + JavaLocalRef name(env, static_cast(env->CallObjectMethod(info, class_info.get_name))); + JavaLocalRef nickname(env, static_cast(env->CallObjectMethod(info, class_info.get_nick))); + JavaLocalRef user_pic(env, env->CallObjectMethod(info, class_info.get_user_pic)); + JavaLocalRef expiry_mode(env, env->CallObjectMethod(info, class_info.get_expiry)); + + auto expiry_pair = util::deserialize_expiry(env, expiry_mode.get()); + auto profile_updated_seconds = env->CallLongMethod(info, class_info.get_profile_updated); + + auto contact_info = conf->get_or_construct(JavaStringRef(env, account_id.get()).view()); + if (name.get()) { + contact_info.name = JavaStringRef(env, name.get()).view(); + } + if (nickname.get()) { + contact_info.nickname = JavaStringRef(env, nickname.get()).view(); + } + contact_info.approved = env->CallBooleanMethod(info, class_info.get_approved); + contact_info.approved_me = env->CallBooleanMethod(info, class_info.get_approved_me); + contact_info.blocked = env->CallBooleanMethod(info, class_info.get_blocked); + contact_info.profile_updated = std::chrono::sys_seconds{std::chrono::seconds{profile_updated_seconds}}; + if (user_pic.get() != nullptr) { + contact_info.profile_picture = util::deserialize_user_pic(env, user_pic.get()); + } + + contact_info.priority = env->CallLongMethod(info, class_info.get_priority); + contact_info.exp_mode = expiry_pair.first; + contact_info.exp_timer = std::chrono::seconds(expiry_pair.second); + + return contact_info; +} + extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_Contacts_get(JNIEnv *env, jobject thiz, jstring account_id) { // If an exception is thrown, return nullptr - return jni_utils::run_catching_cxx_exception_or( + return run_catching_cxx_exception_or_throws( + env, [=]() -> jobject { auto contacts = ptrToContacts(env, thiz); - auto contact = contacts->get(jni_utils::JavaStringRef(env, account_id).view()); + auto contact = contacts->get(JavaStringRef(env, account_id).view()); if (!contact) return nullptr; - jobject j_contact = serialize_contact(env, contact.value()); - return j_contact; - }, - [](const char *) -> jobject { return nullptr; } + return serialize_contact(env, contact.value()).leak(); + } ); } @@ -29,10 +112,10 @@ extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_Contacts_getOrConstruct(JNIEnv *env, jobject thiz, jstring account_id) { - return jni_utils::run_catching_cxx_exception_or_throws(env, [=] { + return run_catching_cxx_exception_or_throws(env, [=] { auto contacts = ptrToContacts(env, thiz); - auto contact = contacts->get_or_construct(jni_utils::JavaStringRef(env, account_id).view()); - return serialize_contact(env, contact); + auto contact = contacts->get_or_construct(JavaStringRef(env, account_id).view()); + return serialize_contact(env, contact).leak(); }); } @@ -40,7 +123,7 @@ extern "C" JNIEXPORT void JNICALL Java_network_loki_messenger_libsession_1util_Contacts_set(JNIEnv *env, jobject thiz, jobject contact) { - jni_utils::run_catching_cxx_exception_or_throws(env, [=] { + run_catching_cxx_exception_or_throws(env, [=] { auto contacts = ptrToContacts(env, thiz); auto contact_info = deserialize_contact(env, contact, contacts); contacts->set(contact_info); @@ -51,9 +134,9 @@ extern "C" JNIEXPORT jboolean JNICALL Java_network_loki_messenger_libsession_1util_Contacts_erase(JNIEnv *env, jobject thiz, jstring account_id) { - return jni_utils::run_catching_cxx_exception_or_throws(env, [=] { + return run_catching_cxx_exception_or_throws(env, [=] { auto contacts = ptrToContacts(env, thiz); - bool result = contacts->erase(jni_utils::JavaStringRef(env, account_id).view()); + bool result = contacts->erase(JavaStringRef(env, account_id).view()); return result; }); } @@ -61,97 +144,34 @@ Java_network_loki_messenger_libsession_1util_Contacts_erase(JNIEnv *env, jobject extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_Contacts_all(JNIEnv *env, jobject thiz) { - return jni_utils::run_catching_cxx_exception_or_throws(env, [=] { - return jni_utils::jlist_from_collection(env, *ptrToContacts(env, thiz), serialize_contact); + return run_catching_cxx_exception_or_throws(env, [=] { + return jlist_from_collection(env, *ptrToContacts(env, thiz), serialize_contact); }); } -jobject serialize_contact(JNIEnv *env, session::config::contact_info info) { - auto contactClass = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/Contact")); - jmethodID constructor = env->GetMethodID(contactClass.get(), "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZLnetwork/loki/messenger/libsession_util/util/UserPic;JJJLnetwork/loki/messenger/libsession_util/util/ExpiryMode;)V"); - jobject returnObj = env->NewObject(contactClass.get(), - constructor, - jni_utils::JavaLocalRef(env, env->NewStringUTF(info.session_id.data())).get(), - jni_utils::JavaLocalRef(env, env->NewStringUTF(info.name.data())).get(), - jni_utils::JavaLocalRef(env, env->NewStringUTF(info.nickname.data())).get(), - (jboolean) info.approved, - (jboolean) info.approved_me, - (jboolean) info.blocked, - jni_utils::JavaLocalRef(env, util::serialize_user_pic(env, info.profile_picture)).get(), - (jlong) info.created, - (jlong) (info.profile_updated.time_since_epoch().count()), - (jlong) info.priority, - util::serialize_expiry(env, info.exp_mode, info.exp_timer)); - return returnObj; -} -session::config::contact_info deserialize_contact(JNIEnv *env, jobject info, session::config::Contacts *conf) { - jclass contactClass = env->FindClass("network/loki/messenger/libsession_util/util/Contact"); - - jfieldID getId, getName, getNick, getApproved, getApprovedMe, getBlocked, getUserPic, getPriority, getExpiry, getHidden, profileUpdatedField; - getId = env->GetFieldID(contactClass, "id", "Ljava/lang/String;"); - getName = env->GetFieldID(contactClass, "name", "Ljava/lang/String;"); - getNick = env->GetFieldID(contactClass, "nickname", "Ljava/lang/String;"); - getApproved = env->GetFieldID(contactClass, "approved", "Z"); - getApprovedMe = env->GetFieldID(contactClass, "approvedMe", "Z"); - getBlocked = env->GetFieldID(contactClass, "blocked", "Z"); - getUserPic = env->GetFieldID(contactClass, "profilePicture", - "Lnetwork/loki/messenger/libsession_util/util/UserPic;"); - getPriority = env->GetFieldID(contactClass, "priority", "J"); - getExpiry = env->GetFieldID(contactClass, "expiryMode", "Lnetwork/loki/messenger/libsession_util/util/ExpiryMode;"); - profileUpdatedField = env->GetFieldID(contactClass, "profileUpdatedEpochSeconds", "J"); - - jni_utils::JavaLocalRef account_id(env, static_cast(env->GetObjectField(info, getId))); - jni_utils::JavaLocalRef name(env, static_cast(env->GetObjectField(info, getName))); - jni_utils::JavaLocalRef nickname(env, static_cast(env->GetObjectField(info, getNick))); - jni_utils::JavaLocalRef user_pic(env, env->GetObjectField(info, getUserPic)); - jni_utils::JavaLocalRef expiry_mode(env, env->GetObjectField(info, getExpiry)); - auto expiry_pair = util::deserialize_expiry(env, expiry_mode.get()); - auto profile_updated_seconds = env->GetLongField(info, profileUpdatedField); +JavaLocalRef serialize_blinded_contact(JNIEnv *env, const session::config::blinded_contact_info &info) { + static BasicJavaClassInfo class_info( + env, "network/loki/messenger/libsession_util/util/BlindedContact", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JJLnetwork/loki/messenger/libsession_util/util/UserPic;J)V"); - auto contact_info = conf->get_or_construct(jni_utils::JavaStringRef(env, account_id.get()).view()); - if (name.get()) { - contact_info.name = jni_utils::JavaStringRef(env, name.get()).view(); - } - if (nickname.get()) { - contact_info.nickname = jni_utils::JavaStringRef(env, nickname.get()).view(); - } - contact_info.approved = env->GetBooleanField(info, getApproved); - contact_info.approved_me = env->GetBooleanField(info, getApprovedMe); - contact_info.blocked = env->GetBooleanField(info, getBlocked); - contact_info.profile_updated = std::chrono::sys_seconds{std::chrono::seconds{profile_updated_seconds}}; - if (user_pic.get() != nullptr) { - contact_info.profile_picture = util::deserialize_user_pic(env, user_pic.get()); - } - - contact_info.priority = env->GetLongField(info, getPriority); - contact_info.exp_mode = expiry_pair.first; - contact_info.exp_timer = std::chrono::seconds(expiry_pair.second); - - return contact_info; -} - -jobject serialize_blinded_contact(JNIEnv *env, const session::config::blinded_contact_info &info) { - jni_utils::JavaLocalRef clazz(env, env->FindClass("network/loki/messenger/libsession_util/util/BlindedContact")); - auto constructor = env->GetMethodID(clazz.get(), "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JJLnetwork/loki/messenger/libsession_util/util/UserPic;J)V"); - - return env->NewObject( - clazz.get(), - constructor, - jni_utils::JavaLocalRef(env, env->NewStringUTF(info.session_id().c_str())).get(), - jni_utils::JavaLocalRef(env, env->NewStringUTF(info.community_base_url().data())).get(), - jni_utils::JavaLocalRef(env, env->NewStringUTF(info.community_pubkey_hex().data())).get(), - jni_utils::JavaLocalRef(env, env->NewStringUTF(info.name.c_str())).get(), + return {env, env->NewObject( + class_info.java_class, + class_info.constructor, + JavaLocalRef(env, env->NewStringUTF(info.session_id().c_str())).get(), + JavaLocalRef(env, env->NewStringUTF(info.community_base_url().data())).get(), + JavaLocalRef(env, env->NewStringUTF(info.community_pubkey_hex().data())).get(), + JavaLocalRef(env, env->NewStringUTF(info.name.c_str())).get(), (jlong) (info.created.time_since_epoch().count()), (jlong) (info.profile_updated.time_since_epoch().count()), - jni_utils::JavaLocalRef(env, util::serialize_user_pic(env, info.profile_picture)).get(), + util::serialize_user_pic(env, info.profile_picture).get(), (jlong) info.priority - ); + )}; } session::config::blinded_contact_info deserialize_blinded_contact(JNIEnv *env, jobject jInfo) { - jni_utils::JavaLocalRef clazz(env, env->GetObjectClass(jInfo)); + JavaLocalRef clazz(env, env->GetObjectClass(jInfo)); auto idField = env->GetFieldID(clazz.get(), "id", "Ljava/lang/String;"); auto communityServerField = env->GetFieldID(clazz.get(), "communityServer", "Ljava/lang/String;"); auto getCommunityServerPubKey = env->GetMethodID(clazz.get(), "getCommunityServerPubKey", "()[B"); @@ -162,13 +182,13 @@ session::config::blinded_contact_info deserialize_blinded_contact(JNIEnv *env, j auto priorityField = env->GetFieldID(clazz.get(), "priority", "J"); session::config::blinded_contact_info info( - jni_utils::JavaStringRef(env, (jstring) env->GetObjectField(jInfo, communityServerField)).view(), - jni_utils::JavaByteArrayRef(env, (jbyteArray) env->CallObjectMethod(jInfo, getCommunityServerPubKey)).get(), - jni_utils::JavaStringRef(env, (jstring) env->GetObjectField(jInfo, idField)).view() + JavaStringRef(env, (jstring) env->GetObjectField(jInfo, communityServerField)).view(), + JavaByteArrayRef(env, (jbyteArray) env->CallObjectMethod(jInfo, getCommunityServerPubKey)).get(), + JavaStringRef(env, (jstring) env->GetObjectField(jInfo, idField)).view() ); info.created = std::chrono::sys_seconds{std::chrono::seconds{env->GetLongField(jInfo, createdEpochSecondsField)}}; - info.profile_picture = util::deserialize_user_pic(env, jni_utils::JavaLocalRef(env, env->GetObjectField(jInfo, profilePicField)).get()); - info.name = jni_utils::JavaStringRef(env, jni_utils::JavaLocalRef(env, (jstring) env->GetObjectField(jInfo, nameField)).get()).view(); + info.profile_picture = util::deserialize_user_pic(env, JavaLocalRef(env, env->GetObjectField(jInfo, profilePicField)).get()); + info.name = JavaStringRef(env, JavaLocalRef(env, (jstring) env->GetObjectField(jInfo, nameField)).get()).view(); info.profile_updated = std::chrono::sys_seconds{std::chrono::seconds{env->GetLongField(jInfo, profileUpdatedEpochSecondsField)}}; info.priority = env->GetLongField(jInfo, priorityField); @@ -183,10 +203,10 @@ Java_network_loki_messenger_libsession_1util_Contacts_getOrConstructBlinded(JNIE jstring community_server_pub_key_hex, jstring blinded_id) { return serialize_blinded_contact(env, ptrToContacts(env, thiz)->get_or_construct_blinded( - jni_utils::JavaStringRef(env, community_server_url).view(), - jni_utils::JavaStringRef(env, community_server_pub_key_hex).view(), - jni_utils::JavaStringRef(env, blinded_id).view() - )); + JavaStringRef(env, community_server_url).view(), + JavaStringRef(env, community_server_pub_key_hex).view(), + JavaStringRef(env, blinded_id).view() + )).leak(); } extern "C" @@ -204,15 +224,15 @@ Java_network_loki_messenger_libsession_1util_Contacts_eraseBlinded(JNIEnv *env, jstring community_server_url, jstring blinded_id) { ptrToContacts(env, thiz)->erase_blinded( - jni_utils::JavaStringRef(env, community_server_url).view(), - jni_utils::JavaStringRef(env, blinded_id).view() + JavaStringRef(env, community_server_url).view(), + JavaStringRef(env, blinded_id).view() ); } extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_Contacts_allBlinded(JNIEnv *env, jobject thiz) { - return jni_utils::jlist_from_collection( + return jlist_from_collection( env, ptrToContacts(env, thiz)->blinded(), serialize_blinded_contact @@ -224,10 +244,10 @@ JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_Contacts_getBlinded(JNIEnv *env, jobject thiz, jstring blinded_id) { - auto result = ptrToContacts(env, thiz)->get_blinded(jni_utils::JavaStringRef(env, blinded_id).view()); + auto result = ptrToContacts(env, thiz)->get_blinded(JavaStringRef(env, blinded_id).view()); if (result) { - return serialize_blinded_contact(env, *result); + return serialize_blinded_contact(env, *result).leak(); } else { return nullptr; } diff --git a/library/src/main/cpp/contacts.h b/library/src/main/cpp/contacts.h index 4122a18..4fa53bd 100644 --- a/library/src/main/cpp/contacts.h +++ b/library/src/main/cpp/contacts.h @@ -4,9 +4,7 @@ #include #include "session/config/contacts.hpp" -session::config::Contacts *ptrToContacts(JNIEnv *env, jobject obj); -jobject serialize_contact(JNIEnv *env, session::config::contact_info info); -session::config::contact_info deserialize_contact(JNIEnv *env, jobject info, session::config::Contacts *conf); + #endif //SESSION_ANDROID_CONTACTS_H diff --git a/library/src/main/cpp/conversation.cpp b/library/src/main/cpp/conversation.cpp index b6a1390..48f2a42 100644 --- a/library/src/main/cpp/conversation.cpp +++ b/library/src/main/cpp/conversation.cpp @@ -1,50 +1,109 @@ #include #include "conversation.h" #include "jni_utils.h" +#include "user_groups.h" +using namespace jni_utils; - jobject serialize_one_to_one(JNIEnv *env, const session::config::convo::one_to_one &one_to_one) { - jni_utils::JavaLocalRef clazz(env, env->FindClass("network/loki/messenger/libsession_util/util/Conversation$OneToOne")); - return env->NewObject(clazz.get(), - env->GetMethodID(clazz.get(), "", "(Ljava/lang/String;JZ)V"), - jni_utils::JavaLocalRef(env, env->NewStringUTF(one_to_one.session_id.data())).get(), + +JavaLocalRef serialize_pro_proof_info(JNIEnv *env, + std::optional> gen_index_hash, + const std::chrono::sys_time & expiry) { + if (!gen_index_hash) { + return {env, nullptr}; + } + + static BasicJavaClassInfo class_info( + env, + "network/loki/messenger/libsession_util/util/Conversation$ProProofInfo", + "([BJ)V" + ); + + return {env, env->NewObject( + class_info.java_class, + class_info.constructor, + util::bytes_from_span(env, *gen_index_hash).get(), + static_cast(expiry.time_since_epoch().count()) + )}; +} + +JavaLocalRef serialize_one_to_one(JNIEnv *env, const session::config::convo::one_to_one &one_to_one) { + static BasicJavaClassInfo class_info( + env, + "network/loki/messenger/libsession_util/util/Conversation$OneToOne", + "(Ljava/lang/String;JZLnetwork/loki/messenger/libsession_util/util/Conversation$ProProofInfo;)V" + ); + + return {env, env->NewObject(class_info.java_class, + class_info.constructor, + JavaLocalRef(env, env->NewStringUTF(one_to_one.session_id.data())).get(), (jlong) one_to_one.last_read, - (jboolean) one_to_one.unread); + (jboolean) one_to_one.unread, + serialize_pro_proof_info(env, one_to_one.pro_gen_index_hash, + one_to_one.pro_expiry_unix_ts).get())}; } session::config::convo::one_to_one deserialize_one_to_one(JNIEnv *env, jobject info) { - jni_utils::JavaLocalRef clazz(env, env->GetObjectClass(info)); + struct ClassInfo { + jclass java_class; + jmethodID id_getter; + jmethodID lastRead_getter; + jmethodID unread_getter; - auto id_getter = env->GetFieldID(clazz.get(), "accountId", "Ljava/lang/String;"); - auto last_read_getter = env->GetFieldID(clazz.get(), "lastRead", "J"); - auto unread_getter = env->GetFieldID(clazz.get(), "unread", "Z"); + ClassInfo(JNIEnv *env, jclass clazz) + :java_class((jclass) env->NewGlobalRef(clazz)), + id_getter(env->GetMethodID(clazz, "getAccountId", "()Ljava/lang/String;")), + lastRead_getter(env->GetMethodID(clazz, "getLastRead", "()J")), + unread_getter(env->GetMethodID(clazz, "getUnread", "()Z")) {} + }; + + static ClassInfo class_info(env, JavaLocalRef(env, env->GetObjectClass(info)).get()); session::config::convo::one_to_one r( - jni_utils::JavaStringRef(env, jni_utils::JavaLocalRef(env, static_cast(env->GetObjectField(info, id_getter))).get()).view() + JavaStringRef( + env, + JavaLocalRef(env, (jstring)(env->CallObjectMethod(info, class_info.id_getter))).get() + ).view() ); - r.last_read = env->GetLongField(info, last_read_getter); - r.unread = env->GetBooleanField(info, unread_getter); + r.last_read = env->CallLongMethod(info, class_info.lastRead_getter); + r.unread = env->CallBooleanMethod(info, class_info.unread_getter); return r; } -jobject serialize_community(JNIEnv *env, const session::config::convo::community& community) { - jni_utils::JavaLocalRef clazz(env, env->FindClass("network/loki/messenger/libsession_util/util/Conversation$Community")); - return env->NewObject(clazz.get(), - env->GetMethodID(clazz.get(), "", - "(Lnetwork/loki/messenger/libsession_util/util/BaseCommunityInfo;JZ)V"), - jni_utils::JavaLocalRef(env, util::serialize_base_community(env, community)).get(), +JavaLocalRef serialize_community(JNIEnv *env, const session::config::convo::community& community) { + static BasicJavaClassInfo class_info( + env, + "network/loki/messenger/libsession_util/util/Conversation$Community", + "(Lnetwork/loki/messenger/libsession_util/util/BaseCommunityInfo;JZ)V" + ); + + return {env, env->NewObject(class_info.java_class, + class_info.constructor, + serialize_base_community(env, community).get(), (jlong) community.last_read, - (jboolean) community.unread); + (jboolean) community.unread)}; } session::config::convo::community deserialize_community(JNIEnv *env, jobject info) { - jni_utils::JavaLocalRef clazz(env, env->GetObjectClass(info)); - auto base_community_getter = env->GetFieldID(clazz.get(), "baseCommunityInfo", "Lnetwork/loki/messenger/libsession_util/util/BaseCommunityInfo;"); - auto last_read_getter = env->GetFieldID(clazz.get(), "lastRead", "J"); - auto unread_getter = env->GetFieldID(clazz.get(), "unread", "Z"); + struct ClassInfo { + jclass java_class; + jmethodID base_community_getter; + jmethodID last_read_getter; + jmethodID unread_getter; + + ClassInfo(JNIEnv *env, jclass clazz) + :java_class((jclass) env->NewGlobalRef(clazz)), + base_community_getter(env->GetMethodID(clazz, "getBaseCommunityInfo", "()Lnetwork/loki/messenger/libsession_util/util/BaseCommunityInfo;")), + last_read_getter(env->GetMethodID(clazz, "getLastRead", "()J")), + unread_getter(env->GetMethodID(clazz, "getUnread", "()Z")) {} + }; + + static ClassInfo class_info(env, JavaLocalRef(env, env->GetObjectClass(info)).get()); - auto base_community = util::deserialize_base_community(env, jni_utils::JavaLocalRef(env, env->GetObjectField(info, base_community_getter)).get()); + auto base_community = deserialize_base_community( + env, + JavaLocalRef(env, env->CallObjectMethod(info, class_info.base_community_getter)).get()); session::config::convo::community community( base_community.base_url(), @@ -52,88 +111,131 @@ session::config::convo::community deserialize_community(JNIEnv *env, jobject inf base_community.pubkey() ); - community.last_read = env->GetLongField(info, last_read_getter); - community.unread = env->GetBooleanField(info, unread_getter); + community.last_read = env->CallLongMethod(info, class_info.last_read_getter); + community.unread = env->CallBooleanMethod(info, class_info.unread_getter); return community; } -jobject serialize_legacy_group(JNIEnv *env, const session::config::convo::legacy_group& group) { - jni_utils::JavaLocalRef clazz(env, env->FindClass("network/loki/messenger/libsession_util/util/Conversation$LegacyGroup")); - return env->NewObject(clazz.get(), - env->GetMethodID(clazz.get(), "","(Ljava/lang/String;JZ)V"), - jni_utils::JavaLocalRef(env, env->NewStringUTF(group.id.data())).get(), +JavaLocalRef serialize_legacy_group(JNIEnv *env, const session::config::convo::legacy_group& group) { + static BasicJavaClassInfo class_info( + env, + "network/loki/messenger/libsession_util/util/Conversation$LegacyGroup", + "(Ljava/lang/String;JZ)V" + ); + + return {env, env->NewObject(class_info.java_class, + class_info.constructor, + JavaLocalRef(env, env->NewStringUTF(group.id.data())).get(), (jlong) group.last_read, - (jboolean) group.unread); + (jboolean) group.unread)}; } session::config::convo::legacy_group deserialize_legacy_closed_group(JNIEnv *env, jobject info) { - jni_utils::JavaLocalRef clazz(env, env->GetObjectClass(info)); - auto group_id_getter = env->GetFieldID(clazz.get(), "groupId", "Ljava/lang/String;"); - auto last_read_getter = env->GetFieldID(clazz.get(), "lastRead", "J"); - auto unread_getter = env->GetFieldID(clazz.get(), "unread", "Z"); + struct ClassInfo { + jclass java_class; + jmethodID groupId_getter; + jmethodID lastRead_getter; + jmethodID unread_getter; + + ClassInfo(JNIEnv *env, jclass clazz) + :java_class((jclass) env->NewGlobalRef(clazz)), + groupId_getter(env->GetMethodID(clazz, "getGroupId", "()Ljava/lang/String;")), + lastRead_getter(env->GetMethodID(clazz, "getLastRead", "()J")), + unread_getter(env->GetMethodID(clazz, "getUnread", "()Z")) {} + }; + + static ClassInfo class_info(env, JavaLocalRef(env, env->GetObjectClass(info)).get()); session::config::convo::legacy_group lg( - jni_utils::JavaStringRef(env, jni_utils::JavaLocalRef(env, static_cast(env->GetObjectField(info, group_id_getter))).get()).view() + JavaStringRef(env, JavaLocalRef(env, static_cast(env->CallObjectMethod(info, class_info.groupId_getter))).get()).view() ); - lg.last_read = env->GetLongField(info, last_read_getter); - lg.unread = env->GetBooleanField(info, unread_getter); + lg.last_read = env->CallLongMethod(info, class_info.lastRead_getter); + lg.unread = env->CallBooleanMethod(info, class_info.unread_getter); return lg; } -jobject serialize_closed_group(JNIEnv* env, const session::config::convo::group &group) { - jni_utils::JavaLocalRef clazz(env, env->FindClass("network/loki/messenger/libsession_util/util/Conversation$ClosedGroup")); - return env->NewObject(clazz.get(), - env->GetMethodID(clazz.get(), "", "(Ljava/lang/String;JZ)V"), - jni_utils::JavaLocalRef(env, env->NewStringUTF(group.id.data())).get(), +JavaLocalRef serialize_closed_group(JNIEnv* env, const session::config::convo::group &group) { + static BasicJavaClassInfo class_info( + env, + "network/loki/messenger/libsession_util/util/Conversation$ClosedGroup", + "(Ljava/lang/String;JZ)V"); + + return {env, env->NewObject(class_info.java_class, + class_info.constructor, + JavaLocalRef(env, env->NewStringUTF(group.id.data())).get(), (jlong) group.last_read, - (jboolean) group.unread); + (jboolean) group.unread)}; } session::config::convo::group deserialize_closed_group(JNIEnv* env, jobject info) { - jni_utils::JavaLocalRef clazz(env, env->GetObjectClass(info)); - auto id_getter = env->GetFieldID(clazz.get(), "accountId", "Ljava/lang/String;"); - auto last_read_getter = env->GetFieldID(clazz.get(), "lastRead", "J"); - auto unread_getter = env->GetFieldID(clazz.get(), "unread", "Z"); + struct ClassInfo { + jclass java_class; + jmethodID id_getter; + jmethodID last_read_getter; + jmethodID unread_getter; + + ClassInfo(JNIEnv *env, jclass clazz) + :java_class((jclass) env->NewGlobalRef(clazz)), + id_getter(env->GetMethodID(clazz, "getAccountId", "()Ljava/lang/String;")), + last_read_getter(env->GetMethodID(clazz, "getLastRead", "()J")), + unread_getter(env->GetMethodID(clazz, "getUnread", "()Z")) {} + }; + + static ClassInfo class_info(env, JavaLocalRef(env, env->GetObjectClass(info)).get()); session::config::convo::group g( - jni_utils::JavaStringRef(env, jni_utils::JavaLocalRef(env, (jstring) env->GetObjectField(info, id_getter)).get()).view()); + JavaStringRef(env, JavaLocalRef(env, (jstring) env->CallObjectMethod(info, class_info.id_getter)).get()).view()); - g.last_read = env->GetLongField(info, last_read_getter); - g.unread = env->GetBooleanField(info, unread_getter); + g.last_read = env->CallLongMethod(info, class_info.last_read_getter); + g.unread = env->CallBooleanMethod(info, class_info.unread_getter); return g; } -jobject serialize_blinded_one_to_one(JNIEnv *env, const session::config::convo::blinded_one_to_one &blinded_one_to_one) { - jni_utils::JavaLocalRef clazz(env, env->FindClass("network/loki/messenger/libsession_util/util/Conversation$BlindedOneToOne")); - return env->NewObject( - clazz.get(), - env->GetMethodID(clazz.get(), "", "(Ljava/lang/String;JZ)V"), - jni_utils::JavaLocalRef(env, env->NewStringUTF(blinded_one_to_one.blinded_session_id.data())).get(), +JavaLocalRef serialize_blinded_one_to_one(JNIEnv *env, const session::config::convo::blinded_one_to_one &blinded_one_to_one) { + static BasicJavaClassInfo class_info( + env, + "network/loki/messenger/libsession_util/util/Conversation$BlindedOneToOne", + "(Ljava/lang/String;JZLnetwork/loki/messenger/libsession_util/util/Conversation$ProProofInfo;)V"); + + return {env, env->NewObject( + class_info.java_class, + class_info.constructor, + JavaLocalRef(env, env->NewStringUTF(blinded_one_to_one.blinded_session_id.data())).get(), (jlong) blinded_one_to_one.last_read, (jboolean) blinded_one_to_one.unread - ); + )}; } session::config::convo::blinded_one_to_one deserialize_blinded_one_to_one(JNIEnv *env, jobject info) { - jni_utils::JavaLocalRef clazz(env, env->GetObjectClass(info)); - auto id_field_id = env->GetFieldID(clazz.get(), "blindedAccountId", "Ljava/lang/String;"); - auto last_read_field_id = env->GetFieldID(clazz.get(), "lastRead", "J"); - auto unread_field_id = env->GetFieldID(clazz.get(), "unread", "Z"); + struct ClassInfo { + jclass java_class; + jmethodID id_getter; + jmethodID last_read_getter; + jmethodID unread_getter; + + ClassInfo(JNIEnv *env, jclass clazz) + :java_class((jclass) env->NewGlobalRef(clazz)), + id_getter(env->GetMethodID(clazz, "getBlindedAccountId", "()Ljava/lang/String;")), + last_read_getter(env->GetMethodID(clazz, "getLastRead", "()J")), + unread_getter(env->GetMethodID(clazz, "getUnread", "()Z")) {} + }; + + static ClassInfo class_info(env, JavaLocalRef(env, env->GetObjectClass(info)).get()); session::config::convo::blinded_one_to_one r( - jni_utils::JavaStringRef(env, jni_utils::JavaLocalRef(env, (jstring) env->GetObjectField(info, id_field_id)).get()).view()); + JavaStringRef(env, JavaLocalRef(env, (jstring) env->CallObjectMethod(info, class_info.id_getter)).get()).view()); - r.last_read = env->GetLongField(info, last_read_field_id); - r.unread = env->GetBooleanField(info, unread_field_id); + r.last_read = env->CallLongMethod(info, class_info.last_read_getter); + r.unread = env->CallBooleanMethod(info, class_info.unread_getter); return r; } -jobject serialize_any(JNIEnv *env, session::config::convo::any any) { +JavaLocalRef serialize_any(JNIEnv *env, session::config::convo::any any) { if (auto* dm = std::get_if(&any)) { return serialize_one_to_one(env, *dm); } else if (auto* og = std::get_if(&any)) { @@ -145,7 +247,7 @@ jobject serialize_any(JNIEnv *env, session::config::convo::any any) { } else if (auto *bc = std::get_if(&any)) { return serialize_blinded_one_to_one(env, *bc); } - return nullptr; + return {env, nullptr}; } @@ -164,17 +266,17 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_eraseAll jobject predicate) { auto conversations = ptrToConvoInfo(env, thiz); - jni_utils::JavaLocalRef predicate_class(env, env->GetObjectClass(predicate)); + JavaLocalRef predicate_class(env, env->GetObjectClass(predicate)); jmethodID predicate_call = env->GetMethodID(predicate_class.get(), "invoke", "(Ljava/lang/Object;)Ljava/lang/Object;"); - jni_utils::JavaLocalRef bool_class(env, env->FindClass("java/lang/Boolean")); + JavaLocalRef bool_class(env, env->FindClass("java/lang/Boolean")); jmethodID bool_get = env->GetMethodID(bool_class.get(), "booleanValue", "()Z"); int removed = 0; auto to_erase = std::vector(); for (auto it = conversations->begin(); it != conversations->end(); ++it) { - jni_utils::JavaLocalRef result(env, env->CallObjectMethod(predicate, predicate_call, jni_utils::JavaLocalRef(env, serialize_any(env, *it)).get())); + JavaLocalRef result(env, env->CallObjectMethod(predicate, predicate_call, serialize_any(env, *it).get())); bool bool_result = env->CallBooleanMethod(result.get(), bool_get); if (bool_result) { to_erase.push_back(*it); @@ -212,9 +314,9 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getOneTo jobject thiz, jstring pub_key_hex) { auto convos = ptrToConvoInfo(env, thiz); - auto internal = convos->get_1to1(jni_utils::JavaStringRef(env, pub_key_hex).view()); + auto internal = convos->get_1to1(JavaStringRef(env, pub_key_hex).view()); if (internal) { - return serialize_one_to_one(env, *internal); + return serialize_one_to_one(env, *internal).leak(); } return nullptr; } @@ -223,7 +325,7 @@ JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getOrConstructOneToOne( JNIEnv *env, jobject thiz, jstring pub_key_hex) { auto convos = ptrToConvoInfo(env, thiz); - return serialize_one_to_one(env, convos->get_or_construct_1to1(jni_utils::JavaStringRef(env, pub_key_hex).view())); + return serialize_one_to_one(env, convos->get_or_construct_1to1(JavaStringRef(env, pub_key_hex).view())).leak(); } extern "C" JNIEXPORT jboolean JNICALL @@ -231,7 +333,7 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_eraseOne jobject thiz, jstring pub_key_hex) { auto convos = ptrToConvoInfo(env, thiz); - return convos->erase_1to1(jni_utils::JavaStringRef(env, pub_key_hex).view()); + return convos->erase_1to1(JavaStringRef(env, pub_key_hex).view()); } extern "C" @@ -239,9 +341,9 @@ JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getCommunity__Ljava_lang_String_2Ljava_lang_String_2( JNIEnv *env, jobject thiz, jstring base_url, jstring room) { auto convos = ptrToConvoInfo(env, thiz); - auto open = convos->get_community(jni_utils::JavaStringRef(env, base_url).view(), jni_utils::JavaStringRef(env, room).view()); + auto open = convos->get_community(JavaStringRef(env, base_url).view(), JavaStringRef(env, room).view()); if (open) { - return serialize_community(env, *open); + return serialize_community(env, *open).leak(); } return nullptr; } @@ -251,10 +353,10 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getOrCon JNIEnv *env, jobject thiz, jstring base_url, jstring room, jbyteArray pub_key) { auto convos = ptrToConvoInfo(env, thiz); auto community = convos->get_or_construct_community( - jni_utils::JavaStringRef(env, base_url).view(), - jni_utils::JavaStringRef(env, room).view(), - jni_utils::JavaByteArrayRef(env, pub_key).get()); - return serialize_community(env, community); + JavaStringRef(env, base_url).view(), + JavaStringRef(env, room).view(), + JavaByteArrayRef(env, pub_key).get()); + return serialize_community(env, community).leak(); } extern "C" JNIEXPORT jobject JNICALL @@ -262,10 +364,10 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getOrCon JNIEnv *env, jobject thiz, jstring base_url, jstring room, jstring pub_key_hex) { auto convos = ptrToConvoInfo(env, thiz); auto community = convos->get_or_construct_community( - jni_utils::JavaStringRef(env, base_url).view(), - jni_utils::JavaStringRef(env, room).view(), - jni_utils::JavaStringRef(env, pub_key_hex).view()); - return serialize_community(env, community); + JavaStringRef(env, base_url).view(), + JavaStringRef(env, room).view(), + JavaStringRef(env, pub_key_hex).view()); + return serialize_community(env, community).leak(); } extern "C" JNIEXPORT jboolean JNICALL @@ -282,17 +384,17 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_eraseCom JNIEnv *env, jobject thiz, jstring base_url, jstring room) { auto convos = ptrToConvoInfo(env, thiz); return convos->erase_community( - jni_utils::JavaStringRef(env, base_url).view(), - jni_utils::JavaStringRef(env, room).view()); + JavaStringRef(env, base_url).view(), + JavaStringRef(env, room).view()); } extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getLegacyClosedGroup( JNIEnv *env, jobject thiz, jstring group_id) { auto convos = ptrToConvoInfo(env, thiz); - auto lgc = convos->get_legacy_group(jni_utils::JavaStringRef(env, group_id).view()); + auto lgc = convos->get_legacy_group(JavaStringRef(env, group_id).view()); if (lgc) { - return serialize_legacy_group(env, *lgc); + return serialize_legacy_group(env, *lgc).leak(); } return nullptr; @@ -302,15 +404,15 @@ JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getOrConstructLegacyGroup( JNIEnv *env, jobject thiz, jstring group_id) { auto convos = ptrToConvoInfo(env, thiz); - auto lgc = convos->get_or_construct_legacy_group(jni_utils::JavaStringRef(env, group_id).view()); - return serialize_legacy_group(env, lgc); + auto lgc = convos->get_or_construct_legacy_group(JavaStringRef(env, group_id).view()); + return serialize_legacy_group(env, lgc).leak(); } extern "C" JNIEXPORT jboolean JNICALL Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_eraseLegacyClosedGroup( JNIEnv *env, jobject thiz, jstring group_id) { auto convos = ptrToConvoInfo(env, thiz); - return convos->erase_legacy_group(jni_utils::JavaStringRef(env, group_id).view()); + return convos->erase_legacy_group(JavaStringRef(env, group_id).view()); } extern "C" @@ -342,14 +444,14 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_all(JNIE jobject thiz) { auto convos = ptrToConvoInfo(env, thiz); - return jni_utils::jlist_from_collection(env, *convos, serialize_any); + return jlist_from_collection(env, *convos, serialize_any); } extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_allOneToOnes(JNIEnv *env, jobject thiz) { auto convos = ptrToConvoInfo(env, thiz); - return jni_utils::jlist_from_iterator(env, convos->begin_1to1(), convos->end(), + return jlist_from_iterator(env, convos->begin_1to1(), convos->end(), serialize_one_to_one); } extern "C" @@ -357,7 +459,7 @@ JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_allCommunities(JNIEnv *env, jobject thiz) { auto convos = ptrToConvoInfo(env, thiz); - return jni_utils::jlist_from_iterator(env, convos->begin_communities(), convos->end(), + return jlist_from_iterator(env, convos->begin_communities(), convos->end(), serialize_community); } extern "C" @@ -365,7 +467,7 @@ JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_allLegacyClosedGroups( JNIEnv *env, jobject thiz) { auto convos = ptrToConvoInfo(env, thiz); - return jni_utils::jlist_from_iterator(env, convos->begin_legacy_groups(), convos->end(), + return jlist_from_iterator(env, convos->begin_legacy_groups(), convos->end(), serialize_legacy_group); } @@ -374,7 +476,7 @@ JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_allClosedGroups(JNIEnv *env, jobject thiz) { auto convos = ptrToConvoInfo(env, thiz); - return jni_utils::jlist_from_iterator(env, convos->begin_groups(), convos->end(), + return jlist_from_iterator(env, convos->begin_groups(), convos->end(), serialize_closed_group); } @@ -384,9 +486,9 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getClose jobject thiz, jstring session_id) { auto config = ptrToConvoInfo(env, thiz); - auto group = config->get_group(jni_utils::JavaStringRef(env, session_id).view()); + auto group = config->get_group(JavaStringRef(env, session_id).view()); if (group) { - return serialize_closed_group(env, *group); + return serialize_closed_group(env, *group).leak(); } return nullptr; } @@ -396,8 +498,8 @@ JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getOrConstructClosedGroup( JNIEnv *env, jobject thiz, jstring session_id) { auto config = ptrToConvoInfo(env, thiz); - auto group = config->get_or_construct_group(jni_utils::JavaStringRef(env, session_id).view()); - return serialize_closed_group(env, group); + auto group = config->get_or_construct_group(JavaStringRef(env, session_id).view()); + return serialize_closed_group(env, group).leak(); } extern "C" @@ -405,7 +507,7 @@ JNIEXPORT jboolean JNICALL Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_eraseClosedGroup( JNIEnv *env, jobject thiz, jstring session_id) { auto config = ptrToConvoInfo(env, thiz); - return config->erase_group(jni_utils::JavaStringRef(env, session_id).view()); + return config->erase_group(JavaStringRef(env, session_id).view()); } extern "C" @@ -447,13 +549,15 @@ extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getOrConstructedBlindedOneToOne( JNIEnv *env, jobject thiz, jstring blinded_id) { - return serialize_blinded_one_to_one(env, ptrToConvoInfo(env, thiz)->get_or_construct_blinded_1to1(jni_utils::JavaStringRef(env, blinded_id).view())); + return serialize_blinded_one_to_one( + env, + ptrToConvoInfo(env, thiz)->get_or_construct_blinded_1to1(JavaStringRef(env, blinded_id).view())).get(); } extern "C" JNIEXPORT jboolean JNICALL Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_eraseBlindedOneToOne( JNIEnv *env, jobject thiz, jstring blinded_id) { - return ptrToConvoInfo(env, thiz)->erase_blinded_1to1(jni_utils::JavaStringRef(env, blinded_id).view()); + return ptrToConvoInfo(env, thiz)->erase_blinded_1to1(JavaStringRef(env, blinded_id).view()); } diff --git a/library/src/main/cpp/curve25519.cpp b/library/src/main/cpp/curve25519.cpp index e4cbe98..2ec9848 100644 --- a/library/src/main/cpp/curve25519.cpp +++ b/library/src/main/cpp/curve25519.cpp @@ -1,4 +1,5 @@ #include "jni_utils.h" +#include "util.h" #include @@ -11,7 +12,7 @@ Java_network_loki_messenger_libsession_1util_Curve25519_fromED25519(JNIEnv *env, auto pk = session::curve25519::to_curve25519_pubkey(jni_utils::JavaByteArrayRef(env, ed25519_public_key).get()); auto sk = session::curve25519::to_curve25519_seckey(jni_utils::JavaByteArrayRef(env, ed25519_private_key).get()); - return jni_utils::new_key_pair(env, util::bytes_from_span(env, pk), util::bytes_from_span(env, sk)); + return jni_utils::new_key_pair(env, util::bytes_from_span(env, pk).get(), util::bytes_from_span(env, sk).get()); }); } @@ -22,7 +23,7 @@ Java_network_loki_messenger_libsession_1util_Curve25519_pubKeyFromED25519(JNIEnv jbyteArray ed25519_public_key) { return jni_utils::run_catching_cxx_exception_or_throws(env, [=] { auto pk = session::curve25519::to_curve25519_pubkey(jni_utils::JavaByteArrayRef(env, ed25519_public_key).get()); - return util::bytes_from_span(env, pk); + return util::bytes_from_span(env, pk).leak(); }); } @@ -32,7 +33,7 @@ Java_network_loki_messenger_libsession_1util_Curve25519_generateKeyPair(JNIEnv * return jni_utils::run_catching_cxx_exception_or_throws(env, [=] { auto [sk, pk] = session::curve25519::curve25519_key_pair(); return jni_utils::new_key_pair(env, - util::bytes_from_span(env, sk), - util::bytes_from_span(env, pk)); + util::bytes_from_span(env, sk).get(), + util::bytes_from_span(env, pk).get()); }); } \ No newline at end of file diff --git a/library/src/main/cpp/ed25519.cpp b/library/src/main/cpp/ed25519.cpp index 1f1c2eb..4de53f2 100644 --- a/library/src/main/cpp/ed25519.cpp +++ b/library/src/main/cpp/ed25519.cpp @@ -14,7 +14,7 @@ Java_network_loki_messenger_libsession_1util_ED25519_sign(JNIEnv *env, jobject t jni_utils::JavaByteArrayRef(env, ed25519_private_key).get(), jni_utils::JavaByteArrayRef(env, message).get()); - return util::bytes_from_vector(env, sigs); + return util::bytes_from_vector(env, sigs).leak(); }); } @@ -42,7 +42,7 @@ Java_network_loki_messenger_libsession_1util_ED25519_generate(JNIEnv *env, jobje ? session::ed25519::ed25519_key_pair(jni_utils::JavaByteArrayRef(env, seed).get()) : session::ed25519::ed25519_key_pair(); - return jni_utils::new_key_pair(env, util::bytes_from_span(env, pk), util::bytes_from_span(env, sk)); + return jni_utils::new_key_pair(env, util::bytes_from_span(env, pk).get(), util::bytes_from_span(env, sk).get()); }); } @@ -56,8 +56,7 @@ Java_network_loki_messenger_libsession_1util_ED25519_generateProMasterKey(JNIEnv session::ed25519::ed25519_pro_privkey_for_ed25519_seed( jni_utils::JavaByteArrayRef(env, ed25519_seed).get() ) - ); - + ).leak(); }); } @@ -70,6 +69,6 @@ Java_network_loki_messenger_libsession_1util_ED25519_positiveEd25519PubKeyFromCu env, session::xed25519::pubkey( jni_utils::JavaByteArrayRef(env, curve25519_pub_key).get()) - ); + ).leak(); }); } \ No newline at end of file diff --git a/library/src/main/cpp/encryption.cpp b/library/src/main/cpp/encryption.cpp index 9ce79e0..48cc471 100644 --- a/library/src/main/cpp/encryption.cpp +++ b/library/src/main/cpp/encryption.cpp @@ -3,6 +3,7 @@ #include #include "jni_utils.h" +#include "util.h" #include @@ -29,8 +30,8 @@ Java_network_loki_messenger_libsession_1util_SessionEncrypt_decryptForBlindedRec return jni_utils::new_kotlin_pair( env, - util::jstringFromOptional(env, session_id), - jni_utils::session_bytes_from_range(env, plain_text) + jni_utils::jstring_from_optional(env, session_id).get(), + jni_utils::session_bytes_from_range(env, plain_text).get() ); }); } @@ -49,7 +50,7 @@ Java_network_loki_messenger_libsession_1util_SessionEncrypt_encryptForRecipient( JavaByteArrayRef(env, message).get() ); - return jni_utils::session_bytes_from_range(env, data); + return jni_utils::session_bytes_from_range(env, data).leak(); }); } @@ -69,8 +70,8 @@ Java_network_loki_messenger_libsession_1util_SessionEncrypt_decryptIncoming(JNIE return jni_utils::new_kotlin_pair( env, - util::jstringFromOptional(env, session_id), - jni_utils::session_bytes_from_range(env, plain_text) + jni_utils::jstring_from_optional(env, session_id).get(), + jni_utils::session_bytes_from_range(env, plain_text).get() ); }); } @@ -91,7 +92,7 @@ Java_network_loki_messenger_libsession_1util_SessionEncrypt_encryptForBlindedRec JavaByteArrayRef(env, message).get() ); - return jni_utils::session_bytes_from_range(env, data); + return jni_utils::session_bytes_from_range(env, data).leak(); }); } @@ -107,7 +108,7 @@ Java_network_loki_messenger_libsession_1util_SessionEncrypt_decryptPushNotificat jni_utils::JavaByteArrayRef(env, secret_key).get() ); - return jni_utils::session_bytes_from_range(env, data); + return jni_utils::session_bytes_from_range(env, data).leak(); }); } @@ -125,7 +126,7 @@ Java_network_loki_messenger_libsession_1util_SessionEncrypt_decryptOnsResponse(J nonce ? std::make_optional(jni_utils::JavaByteArrayRef(env, nonce).get()) : std::nullopt ); - return util::jstringFromOptional(env, data); + return jni_utils::jstring_from_optional(env, data).leak(); }); } @@ -153,7 +154,7 @@ Java_network_loki_messenger_libsession_1util_SessionEncrypt_calculateECHDAgreeme "secret; is the key valid?"}; } - return util::bytes_from_span(env, shared_secret); + return util::bytes_from_span(env, shared_secret).leak(); }); } diff --git a/library/src/main/cpp/group_info.cpp b/library/src/main/cpp/group_info.cpp index bfc13a1..6986658 100644 --- a/library/src/main/cpp/group_info.cpp +++ b/library/src/main/cpp/group_info.cpp @@ -38,21 +38,21 @@ extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_GroupInfoConfig_getCreated(JNIEnv *env, jobject thiz) { auto group_info = ptrToInfo(env, thiz); - return util::jlongFromOptional(env, group_info->get_created()); + return util::jlongFromOptional(env, group_info->get_created()).leak(); } extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_GroupInfoConfig_getDeleteAttachmentsBefore(JNIEnv *env, jobject thiz) { auto group_info = ptrToInfo(env, thiz); - return util::jlongFromOptional(env, group_info->get_delete_attach_before()); + return util::jlongFromOptional(env, group_info->get_delete_attach_before()).leak(); } extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_GroupInfoConfig_getDeleteBefore(JNIEnv *env, jobject thiz) { auto group_info = ptrToInfo(env, thiz); - return util::jlongFromOptional(env, group_info->get_delete_before()); + return util::jlongFromOptional(env, group_info->get_delete_before()).leak(); } extern "C" @@ -72,7 +72,7 @@ extern "C" JNIEXPORT jstring JNICALL Java_network_loki_messenger_libsession_1util_GroupInfoConfig_getName(JNIEnv *env, jobject thiz) { auto group_info = ptrToInfo(env, thiz); - return util::jstringFromOptional(env, group_info->get_name()); + return jni_utils::jstring_from_optional(env, group_info->get_name()).leak(); } extern "C" @@ -80,7 +80,7 @@ JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_GroupInfoConfig_getProfilePic(JNIEnv *env, jobject thiz) { auto group_info = ptrToInfo(env, thiz); - return util::serialize_user_pic(env, group_info->get_profile_pic()); + return util::serialize_user_pic(env, group_info->get_profile_pic()).leak(); } extern "C" @@ -155,7 +155,7 @@ extern "C" JNIEXPORT jstring JNICALL Java_network_loki_messenger_libsession_1util_GroupInfoConfig_id(JNIEnv *env, jobject thiz) { auto group_info = ptrToInfo(env, thiz); - return util::jstringFromOptional(env, group_info->id); + return jni_utils::jstring_from_optional(env, group_info->id).leak(); } extern "C" @@ -167,8 +167,7 @@ Java_network_loki_messenger_libsession_1util_GroupInfoConfig_getDescription(JNIE if (!description) { return nullptr; } - auto jstring = env->NewStringUTF(description->data()); - return jstring; + return env->NewStringUTF(description->data()); } extern "C" diff --git a/library/src/main/cpp/group_keys.cpp b/library/src/main/cpp/group_keys.cpp index 55f43bc..28ddd81 100644 --- a/library/src/main/cpp/group_keys.cpp +++ b/library/src/main/cpp/group_keys.cpp @@ -104,8 +104,7 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_pendingKey(JNIEnv * if (!pending) { return nullptr; } - auto pending_bytes = util::bytes_from_span(env, *pending); - return pending_bytes; + return util::bytes_from_span(env, *pending).leak(); } extern "C" @@ -117,8 +116,7 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_pendingConfig(JNIEn if (!pending) { return nullptr; } - auto pending_bytes = util::bytes_from_span(env, *pending); - return pending_bytes; + return util::bytes_from_span(env, *pending).leak(); } extern "C" @@ -129,8 +127,7 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_rekey(JNIEnv *env, auto info = reinterpret_cast(info_ptr); auto members = reinterpret_cast(members_ptr); auto rekey = keys->rekey(*info, *members); - auto rekey_bytes = util::bytes_from_span(env, rekey); - return rekey_bytes; + return util::bytes_from_span(env, rekey).leak(); } extern "C" @@ -138,8 +135,7 @@ JNIEXPORT jbyteArray JNICALL Java_network_loki_messenger_libsession_1util_GroupKeysConfig_dump(JNIEnv *env, jobject thiz) { auto keys = ptrToKeys(env, thiz); auto dump = keys->dump(); - auto byte_array = util::bytes_from_vector(env, dump); - return byte_array; + return util::bytes_from_vector(env, dump).leak(); } extern "C" @@ -157,7 +153,7 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_encrypt(JNIEnv *env auto ptr = ptrToKeys(env, thiz); auto plaintext_vector = util::vector_from_bytes(env, plaintext); auto enc = ptr->encrypt_message(plaintext_vector); - return util::bytes_from_vector(env, enc); + return util::bytes_from_vector(env, enc).leak(); }); } @@ -172,11 +168,9 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_decrypt(JNIEnv *env auto sender = decrypted.first; auto plaintext = decrypted.second; auto plaintext_bytes = util::bytes_from_vector(env, plaintext); - auto sender_session_id = util::jstringFromOptional(env, sender.data()); - auto pair_class = env->FindClass("kotlin/Pair"); - auto pair_constructor = env->GetMethodID(pair_class, "", "(Ljava/lang/Object;Ljava/lang/Object;)V"); - auto pair_obj = env->NewObject(pair_class, pair_constructor, plaintext_bytes, sender_session_id); - return pair_obj; + auto sender_session_id = jni_utils::jstring_from_optional(env, sender.data()); + + return jni_utils::new_kotlin_pair(env, plaintext_bytes.get(), sender_session_id.get()); }); } @@ -188,10 +182,10 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_keys(JNIEnv *env, j } extern "C" -JNIEXPORT jobject JNICALL +JNIEXPORT jbyteArray 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()); + return util::bytes_from_span(env, ptr->group_enc_key()).leak(); } extern "C" @@ -210,8 +204,7 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_makeSubAccount(JNIE jboolean can_delete) { auto ptr = ptrToKeys(env, thiz); auto new_subaccount_key = ptr->swarm_make_subaccount(jni_utils::JavaStringRef(env, session_id).view(), can_write, can_delete); - auto jbytes = util::bytes_from_vector(env, new_subaccount_key); - return jbytes; + return util::bytes_from_vector(env, new_subaccount_key).leak(); } extern "C" @@ -223,8 +216,18 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_getSubAccountToken( jboolean can_delete) { auto ptr = ptrToKeys(env, thiz); auto token = ptr->swarm_subaccount_token(jni_utils::JavaStringRef(env, session_id).view(), can_write, can_delete); - auto jbytes = util::bytes_from_vector(env, token); - return jbytes; + return util::bytes_from_vector(env, token).leak(); +} + +static jni_utils::JavaLocalRef deserialize_swarm_auth(JNIEnv *env, session::config::groups::Keys::swarm_auth auth) { + static jni_utils::BasicJavaClassInfo class_info( + env, "network/loki/messenger/libsession_util/GroupKeysConfig$SwarmAuth", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + + auto sub_account = jni_utils::JavaLocalRef(env, env->NewStringUTF(auth.subaccount.data())); + auto sub_account_sig = jni_utils::JavaLocalRef(env, env->NewStringUTF(auth.subaccount_sig.data())); + auto signature = jni_utils::JavaLocalRef(env, env->NewStringUTF(auth.signature.data())); + + return {env, env->NewObject(class_info.java_class, class_info.constructor, sub_account.get(), sub_account_sig.get(), signature.get())}; } extern "C" @@ -237,7 +240,7 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_subAccountSign(JNIE auto message_vector = util::vector_from_bytes(env, message); auto signing_value_vector = util::vector_from_bytes(env, signing_value); auto swarm_auth = ptr->swarm_subaccount_sign(message_vector, signing_value_vector, false); - return util::deserialize_swarm_auth(env, swarm_auth); + return deserialize_swarm_auth(env, swarm_auth).leak(); } extern "C" @@ -251,7 +254,7 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_supplementFor(JNIEn user_session_ids.push_back(jni_utils::JavaStringRef(env, jni_utils::JavaLocalRef(env, (jstring)(env->GetObjectArrayElement(j_user_session_ids, i))).get()).copy()); } auto supplement = ptr->key_supplement(user_session_ids); - return util::bytes_from_vector(env, supplement); + return util::bytes_from_vector(env, supplement).leak(); } extern "C" JNIEXPORT jint JNICALL diff --git a/library/src/main/cpp/group_members.cpp b/library/src/main/cpp/group_members.cpp index 8ef9c42..b5a4e13 100644 --- a/library/src/main/cpp/group_members.cpp +++ b/library/src/main/cpp/group_members.cpp @@ -2,6 +2,8 @@ #include "jni_utils.h" +using namespace jni_utils; + extern "C" JNIEXPORT jlong JNICALL Java_network_loki_messenger_libsession_1util_GroupMembersConfig_00024Companion_newInstance( @@ -27,14 +29,14 @@ extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_GroupMembersConfig_all(JNIEnv *env, jobject thiz) { auto config = ptrToMembers(env, thiz); - return jni_utils::jlist_from_collection(env, *config, util::serialize_group_member); + return jlist_from_collection(env, *config, serialize_group_member); } extern "C" JNIEXPORT jboolean JNICALL Java_network_loki_messenger_libsession_1util_GroupMembersConfig_erase(JNIEnv *env, jobject thiz, jstring pub_key_hex) { auto config = ptrToMembers(env, thiz); - auto erased = config->erase(jni_utils::JavaStringRef(env, pub_key_hex).view()); + auto erased = config->erase(JavaStringRef(env, pub_key_hex).view()); return erased; } @@ -42,14 +44,13 @@ extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_GroupMembersConfig_get(JNIEnv *env, jobject thiz, jstring pub_key_hex) { - return jni_utils::run_catching_cxx_exception_or_throws(env, [=]() -> jobject { + return run_catching_cxx_exception_or_throws(env, [=]() -> jobject { auto config = ptrToMembers(env, thiz); - auto member = config->get(jni_utils::JavaStringRef(env, pub_key_hex).view()); + auto member = config->get(JavaStringRef(env, pub_key_hex).view()); if (!member) { return nullptr; } - auto serialized = util::serialize_group_member(env, *member); - return serialized; + return serialize_group_member(env, *member).leak(); }); } @@ -59,9 +60,8 @@ Java_network_loki_messenger_libsession_1util_GroupMembersConfig_getOrConstruct(J jobject thiz, jstring pub_key_hex) { auto config = ptrToMembers(env, thiz); - auto member = config->get_or_construct(jni_utils::JavaStringRef(env, pub_key_hex).view()); - auto serialized = util::serialize_group_member(env, member); - return serialized; + auto member = config->get_or_construct(JavaStringRef(env, pub_key_hex).view()); + return serialize_group_member(env, member).leak(); } extern "C" @@ -138,14 +138,14 @@ extern "C" JNIEXPORT void JNICALL Java_network_loki_messenger_libsession_1util_util_GroupMember_setName(JNIEnv *env, jobject thiz, jstring name) { - ptrToMember(env, thiz)->set_name(std::string(jni_utils::JavaStringRef(env, name).view())); + ptrToMember(env, thiz)->set_name(std::string(JavaStringRef(env, name).view())); } extern "C" JNIEXPORT jstring JNICALL Java_network_loki_messenger_libsession_1util_util_GroupMember_nameString(JNIEnv *env, jobject thiz) { - return util::jstringFromOptional(env, ptrToMember(env, thiz)->name); + return jni_utils::jstring_from_optional(env, ptrToMember(env, thiz)->name).leak(); } extern "C" @@ -165,7 +165,7 @@ extern "C" JNIEXPORT jstring JNICALL Java_network_loki_messenger_libsession_1util_util_GroupMember_accountId(JNIEnv *env, jobject thiz) { - return util::jstringFromOptional(env, ptrToMember(env, thiz)->session_id); + return jni_utils::jstring_from_optional(env, ptrToMember(env, thiz)->session_id).leak(); } extern "C" @@ -178,7 +178,7 @@ extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_util_GroupMember_profilePic(JNIEnv *env, jobject thiz) { - return util::serialize_user_pic(env, ptrToMember(env, thiz)->profile_picture); + return util::serialize_user_pic(env, ptrToMember(env, thiz)->profile_picture).leak(); } extern "C" @@ -210,5 +210,18 @@ Java_network_loki_messenger_libsession_1util_GroupMembersConfig_setPendingSend(J jobject thiz, jstring pub_key_hex, jboolean pending) { - ptrToMembers(env, thiz)->set_pending_send(jni_utils::JavaStringRef(env, pub_key_hex).copy(), pending); + ptrToMembers(env, thiz)->set_pending_send(JavaStringRef(env, pub_key_hex).copy(), pending); +} + +JavaLocalRef serialize_group_member(JNIEnv* env, const session::config::groups::member& member) { + static BasicJavaClassInfo class_info( + env, + "network/loki/messenger/libsession_util/util/GroupMember", + "(J)V"); + + return {env, env->NewObject( + class_info.java_class, + class_info.constructor, + reinterpret_cast(new session::config::groups::member(member)) + )}; } \ No newline at end of file diff --git a/library/src/main/cpp/group_members.h b/library/src/main/cpp/group_members.h index e67329c..91a7bbd 100644 --- a/library/src/main/cpp/group_members.h +++ b/library/src/main/cpp/group_members.h @@ -14,5 +14,6 @@ inline session::config::groups::member *ptrToMember(JNIEnv *env, jobject thiz) { return reinterpret_cast(env->GetLongField(thiz, ptrField)); } +jni_utils::JavaLocalRef serialize_group_member(JNIEnv* env, const session::config::groups::member& member); #endif //SESSION_ANDROID_GROUP_MEMBERS_H diff --git a/library/src/main/cpp/jni_utils.cpp b/library/src/main/cpp/jni_utils.cpp index 75d31cf..3be28c8 100644 --- a/library/src/main/cpp/jni_utils.cpp +++ b/library/src/main/cpp/jni_utils.cpp @@ -2,14 +2,26 @@ namespace jni_utils { jobject new_kotlin_pair(JNIEnv *env, jobject first, jobject second) { - auto pair_class = JavaLocalRef(env, env->FindClass("kotlin/Pair")); - jmethodID constructor = env->GetMethodID(pair_class.get(), "", "(Ljava/lang/Object;Ljava/lang/Object;)V"); - return env->NewObject(pair_class.get(), constructor, first, second); + static BasicJavaClassInfo info(env, "kotlin/Pair", "(Ljava/lang/Object;Ljava/lang/Object;)V"); + return env->NewObject(info.java_class, info.constructor, first, second); } jobject new_key_pair(JNIEnv *env, jbyteArray pubKey, jbyteArray secKey) { - auto kp_class = JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/KeyPair")); - jmethodID kp_constructor = env->GetMethodID(kp_class.get(), "", "([B[B)V"); - return env->NewObject(kp_class.get(), kp_constructor, pubKey, secKey); + static BasicJavaClassInfo class_info( + env, + "network/loki/messenger/libsession_util/util/KeyPair", + "([B[B)V" + ); + + return env->NewObject(class_info.java_class, class_info.constructor, pubKey, secKey); + } + + const ArrayListClassInfo & ArrayListClassInfo::get(JNIEnv *env) { + static ArrayListClassInfo instance(env); + return instance; } -} \ No newline at end of file + + ArrayListClassInfo::ArrayListClassInfo(JNIEnv *env) + :BasicJavaClassInfo(env, "java/util/ArrayList", "()V"), + add_method(env->GetMethodID(java_class, "add", "(Ljava/lang/Object;)Z")) {} +} diff --git a/library/src/main/cpp/jni_utils.h b/library/src/main/cpp/jni_utils.h index 75a6d72..02b8a1e 100644 --- a/library/src/main/cpp/jni_utils.h +++ b/library/src/main/cpp/jni_utils.h @@ -6,8 +6,6 @@ #include #include -#include "util.h" - namespace jni_utils { /** * Run a C++ function and catch any exceptions, throwing a Java exception if one is caught, @@ -62,6 +60,10 @@ namespace jni_utils { class JavaLocalRef { JNIEnv *env_; JNIType ref_; + + template + friend class JavaLocalRef; + public: JavaLocalRef(JNIEnv *env, JNIType ref) : env_(env), ref_(ref) {} ~JavaLocalRef() { @@ -69,7 +71,9 @@ namespace jni_utils { env_->DeleteLocalRef(ref_); } } - JavaLocalRef(JavaLocalRef&& other) : env_(other.env_), ref_(other.ref_) { + + template + JavaLocalRef(JavaLocalRef && other) noexcept : env_(other.env_), ref_(other.ref_) { other.ref_ = nullptr; } @@ -85,8 +89,52 @@ namespace jni_utils { inline JNIType get() const { return ref_; } + + JNIType leak() { + auto r = ref_; + ref_ = nullptr; + return r; + } }; + struct JavaClassInfo { + jclass const java_class; + + JavaClassInfo(JNIEnv *env, const char *class_name) + :java_class((jclass) env->NewGlobalRef(JavaLocalRef(env, env->FindClass(class_name)).get())) {} + + JavaClassInfo(JNIEnv *env, jobject classInstance) + :java_class((jclass) env->NewGlobalRef(JavaLocalRef(env, env->GetObjectClass(classInstance)).get())) {} + }; + + /** + * Convenient way to store information to create a generic Java object + */ + struct BasicJavaClassInfo : public JavaClassInfo { + jmethodID constructor; + + BasicJavaClassInfo(JNIEnv *env, const char *class_name, const char *constructor_signature) + :JavaClassInfo(env, class_name), + constructor(env->GetMethodID(java_class, "", constructor_signature)) { + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + throw std::runtime_error("Failed to find constructor for class " + std::string(class_name)); + } + } + }; + + + /** + * Convenient way to store information to create a Java ArrayList object + */ + struct ArrayListClassInfo: public BasicJavaClassInfo { + jmethodID add_method; + + static const ArrayListClassInfo & get(JNIEnv *env); + + private: + explicit ArrayListClassInfo(JNIEnv *env); + }; /** * Create a Java List from an iterator. @@ -102,22 +150,24 @@ namespace jni_utils { */ template jobject jlist_from_iterator(JNIEnv *env, IterBegin begin, IterEnd end, const ConvertItemFunc &func) { - auto list_clazz = JavaLocalRef(env, env->FindClass("java/util/ArrayList")); - jmethodID init = env->GetMethodID(list_clazz.get(), "", "()V"); - jobject our_list = env->NewObject(list_clazz.get(), init); - jmethodID push = env->GetMethodID(list_clazz.get(), "add", "(Ljava/lang/Object;)Z"); + auto info = ArrayListClassInfo::get(env); + + auto our_list = env->NewObject(info.java_class, info.constructor); for (auto iter = begin; iter != end; ++iter) { - std::optional item_java = func(env, *iter); + std::optional> item_java= func(env, *iter); if (item_java.has_value()) { - env->CallBooleanMethod(our_list, push, *item_java); - env->DeleteLocalRef(*item_java); + env->CallBooleanMethod(our_list, info.add_method, item_java->get()); } } return our_list; } + inline JavaLocalRef jstring_from_optional(JNIEnv* env, std::optional optional) { + return {env, optional ? env->NewStringUTF(optional->data()) : nullptr}; + } + /** * Convenience function to create a Java List from a collection, using the lambda to convert * each item. @@ -136,22 +186,22 @@ namespace jni_utils { */ template jobject jstring_list_from_collection(JNIEnv *env, const Collection& obj) { - return jlist_from_collection(env, obj, util::jstringFromOptional); + return jlist_from_collection(env, obj, jstring_from_optional); } /** * Create a Java Bytes class from the collection. The collection must be continous range of byte data */ template - jobject session_bytes_from_range(JNIEnv *env, const Collection &obj) { - auto bytes_clazz = JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/Bytes")); - jmethodID init = env->GetMethodID(bytes_clazz.get(), "", "([B)V"); + JavaLocalRef session_bytes_from_range(JNIEnv *env, const Collection &obj) { + static BasicJavaClassInfo bytes_class( + env, "network/loki/messenger/libsession_util/util/Bytes", "([B)V"); static_assert(sizeof(*obj.data()) == sizeof(jbyte)); auto bytes_array = JavaLocalRef(env, env->NewByteArray(static_cast(obj.size()))); env->SetByteArrayRegion(bytes_array.get(), 0, static_cast(obj.size()), reinterpret_cast(obj.data())); - return env->NewObject(bytes_clazz.get(), init, bytes_array.get()); + return {env, env->NewObject(bytes_class.java_class, bytes_class.constructor, bytes_array.get())}; } /** diff --git a/library/src/main/cpp/pro_backend.cpp b/library/src/main/cpp/pro_backend.cpp index 54f3561..a5ed5a3 100644 --- a/library/src/main/cpp/pro_backend.cpp +++ b/library/src/main/cpp/pro_backend.cpp @@ -21,7 +21,7 @@ Java_network_loki_messenger_libsession_1util_pro_BackendRequests_buildAddProPaym JavaStringRef(env, payment_id).get_raw(), JavaStringRef(env, order_id).get_raw()); - return util::jstringFromOptional(env, json); + return jni_utils::jstring_from_optional(env, json).leak(); }); } @@ -40,7 +40,7 @@ Java_network_loki_messenger_libsession_1util_pro_BackendRequests_buildGeneratePr } ); - return util::jstringFromOptional(env, json); + return jni_utils::jstring_from_optional(env, json).leak(); }); } @@ -59,7 +59,7 @@ Java_network_loki_messenger_libsession_1util_pro_BackendRequests_buildGetProDeta static_cast(count) ); - return util::jstringFromOptional(env, json); + return jni_utils::jstring_from_optional(env, json).leak(); }); } @@ -77,15 +77,15 @@ Java_network_loki_messenger_libsession_1util_pro_BackendRequests_getPaymentProvi return env->NewObject( clazz, env->GetMethodID(clazz, "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"), - util::jstringFromOptional(env, std::string_view(metadata.device.data, metadata.device.size)), - util::jstringFromOptional(env, std::string_view(metadata.store.data, metadata.store.size)), - util::jstringFromOptional(env, std::string_view(metadata.platform.data, metadata.platform.size)), - util::jstringFromOptional(env, std::string_view(metadata.platform_account.data, metadata.platform_account.size)), - util::jstringFromOptional(env, std::string_view(metadata.refund_platform_url.data, metadata.refund_platform_url.size)), - util::jstringFromOptional(env, std::string_view(metadata.refund_support_url.data, metadata.refund_support_url.size)), - util::jstringFromOptional(env, std::string_view(metadata.refund_status_url.data, metadata.refund_status_url.size)), - util::jstringFromOptional(env, std::string_view(metadata.update_subscription_url.data, metadata.update_subscription_url.size)), - util::jstringFromOptional(env, std::string_view(metadata.cancel_subscription_url.data, metadata.cancel_subscription_url.size)) + jni_utils::jstring_from_optional(env, std::string_view(metadata.device.data, metadata.device.size)).get(), + jni_utils::jstring_from_optional(env, std::string_view(metadata.store.data, metadata.store.size)).get(), + jni_utils::jstring_from_optional(env, std::string_view(metadata.platform.data, metadata.platform.size)).get(), + jni_utils::jstring_from_optional(env, std::string_view(metadata.platform_account.data, metadata.platform_account.size)).get(), + jni_utils::jstring_from_optional(env, std::string_view(metadata.refund_platform_url.data, metadata.refund_platform_url.size)).get(), + jni_utils::jstring_from_optional(env, std::string_view(metadata.refund_support_url.data, metadata.refund_support_url.size)).get(), + jni_utils::jstring_from_optional(env, std::string_view(metadata.refund_status_url.data, metadata.refund_status_url.size)).get(), + jni_utils::jstring_from_optional(env, std::string_view(metadata.update_subscription_url.data, metadata.update_subscription_url.size)).get(), + jni_utils::jstring_from_optional(env, std::string_view(metadata.cancel_subscription_url.data, metadata.cancel_subscription_url.size)).get() ); }); } \ No newline at end of file diff --git a/library/src/main/cpp/pro_proof_util.cpp b/library/src/main/cpp/pro_proof_util.cpp index 2de5b7b..fdc9a5e 100644 --- a/library/src/main/cpp/pro_proof_util.cpp +++ b/library/src/main/cpp/pro_proof_util.cpp @@ -59,10 +59,10 @@ jobject cpp_to_java_proof(JNIEnv *env, const session::ProProof &proof) { pro_proof_clazz.get(), init, static_cast(proof.version), - util::bytes_from_span(env, proof.gen_index_hash), - util::bytes_from_span(env, proof.rotating_pubkey), + util::bytes_from_span(env, proof.gen_index_hash).get(), + util::bytes_from_span(env, proof.rotating_pubkey).get(), static_cast(proof.expiry_unix_ts.time_since_epoch().count()), - util::bytes_from_span(env, proof.sig) + util::bytes_from_span(env, proof.sig).get() ); } diff --git a/library/src/main/cpp/protocol.cpp b/library/src/main/cpp/protocol.cpp index c35a7d7..ac98d18 100644 --- a/library/src/main/cpp/protocol.cpp +++ b/library/src/main/cpp/protocol.cpp @@ -4,46 +4,43 @@ #include "jni_utils.h" #include "pro_proof_util.h" +#include "util.h" using namespace jni_utils; 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(), - "", + static BasicJavaClassInfo class_info( + env, + "network/loki/messenger/libsession_util/protocol/Envelope", "(J[BJ[B)V" - ); + ); - return {env, env->NewObject(envelopClass.get(), - init, + return {env, env->NewObject(class_info.java_class, + class_info.constructor, static_cast(envelope.timestamp.count()), (envelope.flags & SESSION_PROTOCOL_ENVELOPE_FLAGS_SOURCE) - ? util::bytes_from_span(env, envelope.source) + ? util::bytes_from_span(env, envelope.source).get() : nullptr, (envelope.flags & SESSION_PROTOCOL_ENVELOPE_FLAGS_SERVER_TIMESTAMP) ? static_cast(envelope.server_timestamp) : 0, - util::bytes_from_span(env, envelope.pro_sig))}; + util::bytes_from_span(env, envelope.pro_sig).get())}; } -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/DecodedEnvelope")); - jmethodID init = env->GetMethodID( - envelopClass.get(), - "", +static JavaLocalRef serializeDecodedEnvelope(JNIEnv *env, const session::DecodedEnvelope &envelop) { + static BasicJavaClassInfo class_info( + env, + "network/loki/messenger/libsession_util/protocol/DecodedEnvelope", "(Lnetwork/loki/messenger/libsession_util/protocol/Envelope;ILnetwork/loki/messenger/libsession_util/pro/ProProof;J[B[B[BJ)V" ); - return env->NewObject(envelopClass.get(), init, + JavaLocalRef sender_ed25519 = util::bytes_from_span(env, envelop.sender_ed25519_pubkey); + JavaLocalRef sender_x25519 = util::bytes_from_span(env, envelop.sender_x25519_pubkey); + JavaLocalRef content = util::bytes_from_vector(env, envelop.content_plaintext); + + return {env, env->NewObject(class_info.java_class, class_info.constructor, serializeEnvelop(env, envelop.envelope).get(), envelop.pro ? static_cast(envelop.pro->status) : static_cast(-1), @@ -52,7 +49,7 @@ static jobject serializeDecodedEnvelope(JNIEnv *env, const session::DecodedEnvel content.get(), sender_ed25519.get(), sender_x25519.get(), - static_cast(envelop.envelope.timestamp.count())); + static_cast(envelop.envelope.timestamp.count()))}; } @@ -76,7 +73,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeFor1 rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) : std::nullopt ) - ); + ).leak(); }); } @@ -98,7 +95,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeForC rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) : std::nullopt ) - ); + ).leak(); }); } @@ -129,7 +126,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeForG rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) : std::nullopt ) - ); + ).leak(); }); } @@ -163,7 +160,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeForC : static_cast(-1), decoded.pro ? JavaLocalRef(env, cpp_to_java_proof(env, decoded.pro->proof)).get() : nullptr, static_cast(decoded.pro ? decoded.pro->features : 0), - util::bytes_from_vector(env, decoded.content_plaintext) + util::bytes_from_vector(env, decoded.content_plaintext).get() ); }); } @@ -183,7 +180,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeForC rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) : std::nullopt ) - ); + ).leak(); }); } @@ -210,7 +207,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeFor1 std::chrono::sys_time{ std::chrono::milliseconds{now_epoch_ms}}, *java_to_cpp_array<32>(env, pro_backend_pub_key) - )); + )).leak(); }); } @@ -247,7 +244,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeForG std::chrono::sys_time{ std::chrono::milliseconds{now_epoch_ms}}, *java_to_cpp_array<32>(env, pro_backend_pub_key) - )); + )).leak(); }); } diff --git a/library/src/main/cpp/user_groups.cpp b/library/src/main/cpp/user_groups.cpp index 2a60c3b..ab557ca 100644 --- a/library/src/main/cpp/user_groups.cpp +++ b/library/src/main/cpp/user_groups.cpp @@ -3,6 +3,222 @@ #include "session/ed25519.hpp" +using namespace jni_utils; + +inline session::config::UserGroups* ptrToUserGroups(JNIEnv *env, jobject obj) { + auto configClass = JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/UserGroupsConfig")); + jfieldID pointerField = env->GetFieldID(configClass.get(), "pointer", "J"); + return (session::config::UserGroups*) env->GetLongField(obj, pointerField); +} + +static void deserialize_members_into(JNIEnv *env, jobject members_map, session::config::legacy_group_info& to_append_group) { + auto map_class = JavaLocalRef(env, env->FindClass("java/util/Map")); + auto map_entry_class = JavaLocalRef(env, env->FindClass("java/util/Map$Entry")); + auto set_class = JavaLocalRef(env, env->FindClass("java/util/Set")); + auto iterator_class = JavaLocalRef(env, env->FindClass("java/util/Iterator")); + auto boxed_bool = JavaLocalRef(env, env->FindClass("java/lang/Boolean")); + + jmethodID get_entry_set = env->GetMethodID(map_class.get(), "entrySet", "()Ljava/util/Set;"); + jmethodID get_at = env->GetMethodID(set_class.get(), "iterator", "()Ljava/util/Iterator;"); + jmethodID has_next = env->GetMethodID(iterator_class.get(), "hasNext", "()Z"); + jmethodID next = env->GetMethodID(iterator_class.get(), "next", "()Ljava/lang/Object;"); + jmethodID get_key = env->GetMethodID(map_entry_class.get(), "getKey", "()Ljava/lang/Object;"); + jmethodID get_value = env->GetMethodID(map_entry_class.get(), "getValue", "()Ljava/lang/Object;"); + jmethodID get_bool_value = env->GetMethodID(boxed_bool.get(), "booleanValue", "()Z"); + + auto entry_set = JavaLocalRef(env, env->CallObjectMethod(members_map, get_entry_set)); + auto iterator = JavaLocalRef(env, env->CallObjectMethod(entry_set.get(), get_at)); + + while (env->CallBooleanMethod(iterator.get(), has_next)) { + JavaLocalRef entry(env, env->CallObjectMethod(iterator.get(), next)); + JavaLocalRef key(env, static_cast(env->CallObjectMethod(entry.get(), get_key))); + JavaLocalRef boxed(env, env->CallObjectMethod(entry.get(), get_value)); + bool is_admin = env->CallBooleanMethod(boxed.get(), get_bool_value); + to_append_group.insert(std::string(JavaStringRef(env, key.get()).view()), is_admin); + } +} + + +static session::config::legacy_group_info deserialize_legacy_group_info(JNIEnv *env, jobject info, session::config::UserGroups* conf) { + auto clazz = JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$LegacyGroupInfo")); + auto id_field = env->GetFieldID(clazz.get(), "accountId", "Ljava/lang/String;"); + auto name_field = env->GetFieldID(clazz.get(), "name", "Ljava/lang/String;"); + auto members_field = env->GetFieldID(clazz.get(), "members", "Ljava/util/Map;"); + auto enc_pub_key_method = env->GetMethodID(clazz.get(), "getEncPubKeyAsByteArray", "()[B"); + auto enc_sec_key_method = env->GetMethodID(clazz.get(), "getEncSecKeyAsByteArray", "()[B"); + auto priority_field = env->GetFieldID(clazz.get(), "priority", "J"); + auto disappearing_timer_field = env->GetFieldID(clazz.get(), "disappearingTimer", "J"); + auto joined_at_field = env->GetFieldID(clazz.get(), "joinedAtSecs", "J"); + auto id = JavaLocalRef(env, static_cast(env->GetObjectField(info, id_field))); + auto name = JavaLocalRef(env, static_cast(env->GetObjectField(info, name_field))); + auto members_map = JavaLocalRef(env, env->GetObjectField(info, members_field)); + auto enc_pub_key = JavaLocalRef(env, static_cast(env->CallObjectMethod(info, enc_pub_key_method))); + auto enc_sec_key = JavaLocalRef(env, static_cast(env->CallObjectMethod(info, enc_sec_key_method))); + int priority = env->GetLongField(info, priority_field); + long joined_at = env->GetLongField(info, joined_at_field); + + auto info_deserialized = conf->get_or_construct_legacy_group(JavaStringRef(env, id.get()).view()); + + auto current_members = info_deserialized.members(); + for (auto member = current_members.begin(); member != current_members.end(); ++member) { + info_deserialized.erase(member->first); + } + deserialize_members_into(env, members_map.get(), info_deserialized); + info_deserialized.name = JavaStringRef(env, name.get()).view(); + info_deserialized.enc_pubkey = JavaByteArrayRef(env, enc_pub_key.get()).copy(); + info_deserialized.enc_seckey = JavaByteArrayRef(env, enc_sec_key.get()).copy(); + info_deserialized.priority = priority; + info_deserialized.disappearing_timer = std::chrono::seconds(env->GetLongField(info, disappearing_timer_field)); + info_deserialized.joined_at = joined_at; + return info_deserialized; +} + +static session::config::community_info deserialize_community_info(JNIEnv *env, jobject info, session::config::UserGroups* conf) { + auto clazz = JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$CommunityGroupInfo")); + auto base_info = env->GetFieldID(clazz.get(), "community", "Lnetwork/loki/messenger/libsession_util/util/BaseCommunityInfo;"); + auto priority = env->GetFieldID(clazz.get(), "priority", "J"); + auto base_community_info = JavaLocalRef(env, env->GetObjectField(info, base_info)); + auto deserialized_base_info = deserialize_base_community(env, base_community_info.get()); + int deserialized_priority = env->GetLongField(info, priority); + auto community_info = conf->get_or_construct_community(deserialized_base_info.base_url(), deserialized_base_info.room(), deserialized_base_info.pubkey_hex()); + community_info.priority = deserialized_priority; + return community_info; +} + +static jobject serialize_members(JNIEnv *env, std::map members_map) { + auto map_class = JavaLocalRef(env, env->FindClass("java/util/HashMap")); + auto boxed_bool = JavaLocalRef(env, env->FindClass("java/lang/Boolean")); + jmethodID map_constructor = env->GetMethodID(map_class.get(), "", "()V"); + jmethodID insert = env->GetMethodID(map_class.get(), "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + jmethodID new_bool = env->GetMethodID(boxed_bool.get(), "", "(Z)V"); + + auto new_map = env->NewObject(map_class.get(), map_constructor); + for (auto it = members_map.begin(); it != members_map.end(); it++) { + auto account_id = JavaLocalRef(env, env->NewStringUTF(it->first.data())); + bool is_admin = it->second; + auto jbool = JavaLocalRef(env, env->NewObject(boxed_bool.get(), new_bool, is_admin)); + env->CallObjectMethod(new_map, insert, account_id.get(), jbool.get()); + } + return new_map; +} + +static JavaLocalRef serialize_legacy_group_info(JNIEnv *env, session::config::legacy_group_info info) { + auto account_id = JavaLocalRef(env, env->NewStringUTF(info.session_id.data())); + auto name = JavaLocalRef(env, env->NewStringUTF(info.name.data())); + auto members = JavaLocalRef(env, serialize_members(env, info.members())); + auto enc_pubkey = session_bytes_from_range(env, info.enc_pubkey); + auto enc_seckey = session_bytes_from_range(env, info.enc_seckey); + long long priority = info.priority; + long long joined_at = info.joined_at; + + static BasicJavaClassInfo class_info( + env, + "network/loki/messenger/libsession_util/util/GroupInfo$LegacyGroupInfo", + "(Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Lnetwork/loki/messenger/libsession_util/util/Bytes;Lnetwork/loki/messenger/libsession_util/util/Bytes;JJJ)V" + ); + + return {env, env->NewObject(class_info.java_class, class_info.constructor, + account_id.get(), name.get(), members.get(), enc_pubkey.get(), + enc_seckey.get(), priority, + (jlong) info.disappearing_timer.count(), joined_at)}; +} + +static JavaLocalRef serialize_closed_group_info(JNIEnv* env, session::config::group_info info) { + auto session_id = jstring_from_optional(env, info.id); + auto admin_bytes = JavaLocalRef(env, info.secretkey.empty() ? nullptr : session_bytes_from_range(env, info.secretkey).leak()); + auto auth_bytes = JavaLocalRef(env, info.auth_data.empty() ? nullptr : session_bytes_from_range(env, info.auth_data).leak()); + auto name = jstring_from_optional(env, info.name); + + static BasicJavaClassInfo class_info( + env, + "network/loki/messenger/libsession_util/util/GroupInfo$ClosedGroupInfo", + "(Ljava/lang/String;Lnetwork/loki/messenger/libsession_util/util/Bytes;Lnetwork/loki/messenger/libsession_util/util/Bytes;JZLjava/lang/String;ZZJ)V" + ); + + return {env, env->NewObject(class_info.java_class, class_info.constructor, + session_id.get(), admin_bytes.get(), auth_bytes.get(), (jlong)info.priority, info.invited, name.get(), + info.kicked(), info.is_destroyed(), info.joined_at)}; +} + +static session::config::group_info deserialize_closed_group_info(JNIEnv* env, jobject info_serialized) { + auto closed_group_class = JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$ClosedGroupInfo")); + jfieldID id_field = env->GetFieldID(closed_group_class.get(), "groupAccountId", "Ljava/lang/String;"); + auto secret_method = env->GetMethodID(closed_group_class.get(), "getAdminKeyAsByteArray", "()[B"); + auto auth_method = env->GetMethodID(closed_group_class.get(), "getAuthDataAsByteArray", "()[B"); + jfieldID priority_field = env->GetFieldID(closed_group_class.get(), "priority", "J"); + jfieldID invited_field = env->GetFieldID(closed_group_class.get(), "invited", "Z"); + jfieldID name_field = env->GetFieldID(closed_group_class.get(), "name", "Ljava/lang/String;"); + jfieldID destroy_field = env->GetFieldID(closed_group_class.get(), "destroyed", "Z"); + jfieldID kicked_field = env->GetFieldID(closed_group_class.get(), "kicked", "Z"); + jfieldID joined_at_field = env->GetFieldID(closed_group_class.get(), "joinedAtSecs", "J"); + + + auto id_jobject = JavaLocalRef(env, static_cast(env->GetObjectField(info_serialized, id_field))); + auto secret_jBytes = JavaLocalRef(env, (jbyteArray)env->CallObjectMethod(info_serialized, secret_method)); + auto auth_jBytes = JavaLocalRef(env, (jbyteArray)env->CallObjectMethod(info_serialized, auth_method)); + auto name_jstring = JavaLocalRef(env, (jstring)env->GetObjectField(info_serialized, name_field)); + + auto secret_bytes = util::vector_from_bytes(env, secret_jBytes.get()); + auto auth_bytes = util::vector_from_bytes(env, auth_jBytes.get()); + + session::config::group_info group_info(JavaStringRef(env, id_jobject.get()).copy()); + group_info.auth_data = auth_bytes; + group_info.secretkey = secret_bytes; + group_info.priority = env->GetLongField(info_serialized, priority_field); + group_info.invited = env->GetBooleanField(info_serialized, invited_field); + group_info.name = JavaStringRef(env, name_jstring.get()).view(); + group_info.joined_at = env->GetLongField(info_serialized, joined_at_field); + + if (env->GetBooleanField(info_serialized, kicked_field)) { + group_info.mark_kicked(); + } + + if (env->GetBooleanField(info_serialized, destroy_field)) { + group_info.mark_destroyed(); + } + + return group_info; +} + +static JavaLocalRef serialize_community_info(JNIEnv *env, session::config::community_info info) { + auto priority = (long long)info.priority; + auto serialized_info = serialize_base_community(env, info); + + static BasicJavaClassInfo class_info( + env, + "network/loki/messenger/libsession_util/util/GroupInfo$CommunityGroupInfo", + "(Lnetwork/loki/messenger/libsession_util/util/BaseCommunityInfo;J)V" + ); + + return {env, env->NewObject(class_info.java_class, class_info.constructor, serialized_info.get(), priority)}; +} + +JavaLocalRef serialize_base_community(JNIEnv *env, const session::config::community& community) { + auto base_community_clazz = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/BaseCommunityInfo")); + jmethodID base_community_constructor = env->GetMethodID(base_community_clazz.get(), "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + auto base_url = jni_utils::JavaLocalRef(env, env->NewStringUTF(community.base_url().data())); + auto room = jni_utils::JavaLocalRef(env, env->NewStringUTF(community.room().data())); + auto pubkey_jstring = jni_utils::JavaLocalRef(env, env->NewStringUTF(community.pubkey_hex().data())); + return {env, env->NewObject(base_community_clazz.get(), base_community_constructor, base_url.get(), room.get(), pubkey_jstring.get())}; +} + +session::config::community deserialize_base_community(JNIEnv *env, jobject base_community) { + jclass base_community_clazz = env->FindClass("network/loki/messenger/libsession_util/util/BaseCommunityInfo"); + jfieldID base_url_field = env->GetFieldID(base_community_clazz, "baseUrl", "Ljava/lang/String;"); + jfieldID room_field = env->GetFieldID(base_community_clazz, "room", "Ljava/lang/String;"); + jfieldID pubkey_hex_field = env->GetFieldID(base_community_clazz, "pubKeyHex", "Ljava/lang/String;"); + jni_utils::JavaLocalRef base_url(env, (jstring)env->GetObjectField(base_community,base_url_field)); + jni_utils::JavaLocalRef room(env, (jstring)env->GetObjectField(base_community, room_field)); + jni_utils::JavaLocalRef pub_key_hex(env, (jstring)env->GetObjectField(base_community, pubkey_hex_field)); + + return session::config::community( + jni_utils::JavaStringRef(env, base_url.get()).view(), + jni_utils::JavaStringRef(env, room.get()).view(), + jni_utils::JavaStringRef(env, pub_key_hex.get()).view() + ); +} + + extern "C" JNIEXPORT jint JNICALL Java_network_loki_messenger_libsession_1util_util_GroupInfo_00024LegacyGroupInfo_00024Companion_NAME_1MAX_1LENGTH( @@ -18,10 +234,10 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_getCommunityInfo(J jstring room) { auto conf = ptrToUserGroups(env, thiz); - auto community = conf->get_community(jni_utils::JavaStringRef(env, base_url).view(), jni_utils::JavaStringRef(env, room).view()); + auto community = conf->get_community(JavaStringRef(env, base_url).view(), JavaStringRef(env, room).view()); if (community) { - return serialize_community_info(env, *community); + return serialize_community_info(env, *community).leak(); } return nullptr; @@ -33,10 +249,10 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_getLegacyGroupInfo jobject thiz, jstring account_id) { auto conf = ptrToUserGroups(env, thiz); - auto legacy_group = conf->get_legacy_group(jni_utils::JavaStringRef(env, account_id).view()); + auto legacy_group = conf->get_legacy_group(JavaStringRef(env, account_id).view()); jobject return_group = nullptr; if (legacy_group) { - return_group = serialize_legacy_group_info(env, *legacy_group); + return_group = serialize_legacy_group_info(env, *legacy_group).leak(); } return return_group; } @@ -48,11 +264,11 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_getOrConstructComm auto conf = ptrToUserGroups(env, thiz); auto group = conf->get_or_construct_community( - jni_utils::JavaStringRef(env, base_url).view(), - jni_utils::JavaStringRef(env, room).view(), - jni_utils::JavaStringRef(env, pub_key_hex).view()); + JavaStringRef(env, base_url).view(), + JavaStringRef(env, room).view(), + JavaStringRef(env, pub_key_hex).view()); - return serialize_community_info(env, group); + return serialize_community_info(env, group).leak(); } extern "C" @@ -60,8 +276,8 @@ JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_UserGroupsConfig_getOrConstructLegacyGroupInfo( JNIEnv *env, jobject thiz, jstring account_id) { auto conf = ptrToUserGroups(env, thiz); - auto group = conf->get_or_construct_legacy_group(jni_utils::JavaStringRef(env, account_id).view()); - return serialize_legacy_group_info(env, group); + auto group = conf->get_or_construct_legacy_group(JavaStringRef(env, account_id).view()); + return serialize_legacy_group_info(env, group).leak(); } extern "C" @@ -132,8 +348,8 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_size(JNIEnv *env, } inline jobject iterator_as_java_list(JNIEnv *env, session::config::UserGroups::iterator begin, session::config::UserGroups::iterator end) { - return jni_utils::jlist_from_iterator(env, begin, end, [](JNIEnv *env, const session::config::UserGroups::value_type &item) { - std::optional serialized = std::nullopt; + return jlist_from_iterator(env, begin, end, [](JNIEnv *env, const session::config::UserGroups::value_type &item) { + std::optional> serialized = std::nullopt; if (auto* lgc = std::get_if(&item)) { serialized = serialize_legacy_group_info(env, *lgc); } else if (auto* community = std::get_if(&item)) { @@ -175,7 +391,7 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_eraseCommunity__Ln jobject thiz, jobject base_community_info) { auto conf = ptrToUserGroups(env, thiz); - auto base_community = util::deserialize_base_community(env, base_community_info); + auto base_community = deserialize_base_community(env, base_community_info); return conf->erase_community(base_community.base_url(),base_community.room()); } @@ -185,8 +401,8 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_eraseCommunity__Lj JNIEnv *env, jobject thiz, jstring server, jstring room) { auto conf = ptrToUserGroups(env, thiz); auto community = conf->get_community( - jni_utils::JavaStringRef(env, server).view(), - jni_utils::JavaStringRef(env, room).view()); + JavaStringRef(env, server).view(), + JavaStringRef(env, room).view()); bool deleted = false; if (community) { deleted = conf->erase(*community); @@ -200,7 +416,7 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_eraseLegacyGroup(J jobject thiz, jstring account_id) { auto conf = ptrToUserGroups(env, thiz); - bool return_bool = conf->erase_legacy_group(jni_utils::JavaStringRef(env, account_id).view()); + bool return_bool = conf->erase_legacy_group(JavaStringRef(env, account_id).view()); return return_bool; } @@ -210,10 +426,10 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_getClosedGroup(JNI jobject thiz, jstring session_id) { auto config = ptrToUserGroups(env, thiz); - auto group = config->get_group(jni_utils::JavaStringRef(env, session_id).view()); + auto group = config->get_group(JavaStringRef(env, session_id).view()); if (group) { - return serialize_closed_group_info(env, *group); + return serialize_closed_group_info(env, *group).leak(); } return nullptr; } @@ -224,8 +440,8 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_getOrConstructClos jobject thiz, jstring session_id) { auto config = ptrToUserGroups(env, thiz); - auto group = config->get_or_construct_group(jni_utils::JavaStringRef(env, session_id).view()); - return serialize_closed_group_info(env, group); + auto group = config->get_or_construct_group(JavaStringRef(env, session_id).view()); + return serialize_closed_group_info(env, group).leak(); } extern "C" @@ -243,7 +459,7 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_createGroup(JNIEnv auto config = ptrToUserGroups(env, thiz); auto group = config->create_group(); - return serialize_closed_group_info(env, group); + return serialize_closed_group_info(env, group).leak(); } extern "C" @@ -260,7 +476,7 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_eraseClosedGroup(J jobject thiz, jstring session_id) { auto config = ptrToUserGroups(env, thiz); - bool return_value = config->erase_group(jni_utils::JavaStringRef(env, session_id).view()); + bool return_value = config->erase_group(JavaStringRef(env, session_id).view()); return return_value; } @@ -275,7 +491,7 @@ Java_network_loki_messenger_libsession_1util_util_GroupInfo_00024ClosedGroupInfo } auto admin_key = session::ed25519::ed25519_key_pair( - jni_utils::JavaByteArrayRef(env, seed).get()).second; + JavaByteArrayRef(env, seed).get()).second; - return util::bytes_from_span(env, std::span(admin_key.data(), admin_key.size())); + return util::bytes_from_span(env, std::span(admin_key.data(), admin_key.size())).leak(); } \ No newline at end of file diff --git a/library/src/main/cpp/user_groups.h b/library/src/main/cpp/user_groups.h index 7efbafa..95595d5 100644 --- a/library/src/main/cpp/user_groups.h +++ b/library/src/main/cpp/user_groups.h @@ -8,176 +8,7 @@ #include "conversation.h" #include "session/config/user_groups.hpp" -inline session::config::UserGroups* ptrToUserGroups(JNIEnv *env, jobject obj) { - auto configClass = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/UserGroupsConfig")); - jfieldID pointerField = env->GetFieldID(configClass.get(), "pointer", "J"); - return (session::config::UserGroups*) env->GetLongField(obj, pointerField); -} - -inline void deserialize_members_into(JNIEnv *env, jobject members_map, session::config::legacy_group_info& to_append_group) { - auto map_class = jni_utils::JavaLocalRef(env, env->FindClass("java/util/Map")); - auto map_entry_class = jni_utils::JavaLocalRef(env, env->FindClass("java/util/Map$Entry")); - auto set_class = jni_utils::JavaLocalRef(env, env->FindClass("java/util/Set")); - auto iterator_class = jni_utils::JavaLocalRef(env, env->FindClass("java/util/Iterator")); - auto boxed_bool = jni_utils::JavaLocalRef(env, env->FindClass("java/lang/Boolean")); - - jmethodID get_entry_set = env->GetMethodID(map_class.get(), "entrySet", "()Ljava/util/Set;"); - jmethodID get_at = env->GetMethodID(set_class.get(), "iterator", "()Ljava/util/Iterator;"); - jmethodID has_next = env->GetMethodID(iterator_class.get(), "hasNext", "()Z"); - jmethodID next = env->GetMethodID(iterator_class.get(), "next", "()Ljava/lang/Object;"); - jmethodID get_key = env->GetMethodID(map_entry_class.get(), "getKey", "()Ljava/lang/Object;"); - jmethodID get_value = env->GetMethodID(map_entry_class.get(), "getValue", "()Ljava/lang/Object;"); - jmethodID get_bool_value = env->GetMethodID(boxed_bool.get(), "booleanValue", "()Z"); - - auto entry_set = jni_utils::JavaLocalRef(env, env->CallObjectMethod(members_map, get_entry_set)); - auto iterator = jni_utils::JavaLocalRef(env, env->CallObjectMethod(entry_set.get(), get_at)); - - while (env->CallBooleanMethod(iterator.get(), has_next)) { - jni_utils::JavaLocalRef entry(env, env->CallObjectMethod(iterator.get(), next)); - jni_utils::JavaLocalRef key(env, static_cast(env->CallObjectMethod(entry.get(), get_key))); - jni_utils::JavaLocalRef boxed(env, env->CallObjectMethod(entry.get(), get_value)); - bool is_admin = env->CallBooleanMethod(boxed.get(), get_bool_value); - to_append_group.insert(std::string(jni_utils::JavaStringRef(env, key.get()).view()), is_admin); - } -} - -inline session::config::legacy_group_info deserialize_legacy_group_info(JNIEnv *env, jobject info, session::config::UserGroups* conf) { - auto clazz = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$LegacyGroupInfo")); - auto id_field = env->GetFieldID(clazz.get(), "accountId", "Ljava/lang/String;"); - auto name_field = env->GetFieldID(clazz.get(), "name", "Ljava/lang/String;"); - auto members_field = env->GetFieldID(clazz.get(), "members", "Ljava/util/Map;"); - auto enc_pub_key_method = env->GetMethodID(clazz.get(), "getEncPubKeyAsByteArray", "()[B"); - auto enc_sec_key_method = env->GetMethodID(clazz.get(), "getEncSecKeyAsByteArray", "()[B"); - auto priority_field = env->GetFieldID(clazz.get(), "priority", "J"); - auto disappearing_timer_field = env->GetFieldID(clazz.get(), "disappearingTimer", "J"); - auto joined_at_field = env->GetFieldID(clazz.get(), "joinedAtSecs", "J"); - auto id = jni_utils::JavaLocalRef(env, static_cast(env->GetObjectField(info, id_field))); - auto name = jni_utils::JavaLocalRef(env, static_cast(env->GetObjectField(info, name_field))); - auto members_map = jni_utils::JavaLocalRef(env, env->GetObjectField(info, members_field)); - auto enc_pub_key = jni_utils::JavaLocalRef(env, static_cast(env->CallObjectMethod(info, enc_pub_key_method))); - auto enc_sec_key = jni_utils::JavaLocalRef(env, static_cast(env->CallObjectMethod(info, enc_sec_key_method))); - int priority = env->GetLongField(info, priority_field); - long joined_at = env->GetLongField(info, joined_at_field); - - auto info_deserialized = conf->get_or_construct_legacy_group(jni_utils::JavaStringRef(env, id.get()).view()); - - auto current_members = info_deserialized.members(); - for (auto member = current_members.begin(); member != current_members.end(); ++member) { - info_deserialized.erase(member->first); - } - deserialize_members_into(env, members_map.get(), info_deserialized); - info_deserialized.name = jni_utils::JavaStringRef(env, name.get()).view(); - info_deserialized.enc_pubkey = jni_utils::JavaByteArrayRef(env, enc_pub_key.get()).copy(); - info_deserialized.enc_seckey = jni_utils::JavaByteArrayRef(env, enc_sec_key.get()).copy(); - info_deserialized.priority = priority; - info_deserialized.disappearing_timer = std::chrono::seconds(env->GetLongField(info, disappearing_timer_field)); - info_deserialized.joined_at = joined_at; - return info_deserialized; -} - -inline session::config::community_info deserialize_community_info(JNIEnv *env, jobject info, session::config::UserGroups* conf) { - auto clazz = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$CommunityGroupInfo")); - auto base_info = env->GetFieldID(clazz.get(), "community", "Lnetwork/loki/messenger/libsession_util/util/BaseCommunityInfo;"); - auto priority = env->GetFieldID(clazz.get(), "priority", "J"); - auto base_community_info = jni_utils::JavaLocalRef(env, env->GetObjectField(info, base_info)); - auto deserialized_base_info = util::deserialize_base_community(env, base_community_info.get()); - int deserialized_priority = env->GetLongField(info, priority); - auto community_info = conf->get_or_construct_community(deserialized_base_info.base_url(), deserialized_base_info.room(), deserialized_base_info.pubkey_hex()); - community_info.priority = deserialized_priority; - return community_info; -} - -inline jobject serialize_members(JNIEnv *env, std::map members_map) { - auto map_class = jni_utils::JavaLocalRef(env, env->FindClass("java/util/HashMap")); - auto boxed_bool = jni_utils::JavaLocalRef(env, env->FindClass("java/lang/Boolean")); - jmethodID map_constructor = env->GetMethodID(map_class.get(), "", "()V"); - jmethodID insert = env->GetMethodID(map_class.get(), "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); - jmethodID new_bool = env->GetMethodID(boxed_bool.get(), "", "(Z)V"); - - auto new_map = env->NewObject(map_class.get(), map_constructor); - for (auto it = members_map.begin(); it != members_map.end(); it++) { - auto account_id = jni_utils::JavaLocalRef(env, env->NewStringUTF(it->first.data())); - bool is_admin = it->second; - auto jbool = jni_utils::JavaLocalRef(env, env->NewObject(boxed_bool.get(), new_bool, is_admin)); - env->CallObjectMethod(new_map, insert, account_id.get(), jbool.get()); - } - return new_map; -} - -inline jobject serialize_legacy_group_info(JNIEnv *env, session::config::legacy_group_info info) { - auto account_id = jni_utils::JavaLocalRef(env, env->NewStringUTF(info.session_id.data())); - auto name = jni_utils::JavaLocalRef(env, env->NewStringUTF(info.name.data())); - auto members = jni_utils::JavaLocalRef(env, serialize_members(env, info.members())); - auto enc_pubkey = jni_utils::session_bytes_from_range(env, info.enc_pubkey); - auto enc_seckey = jni_utils::session_bytes_from_range(env, info.enc_seckey); - long long priority = info.priority; - long long joined_at = info.joined_at; - - auto legacy_group_class = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$LegacyGroupInfo")); - jmethodID constructor = env->GetMethodID(legacy_group_class.get(), "", "(Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Lnetwork/loki/messenger/libsession_util/util/Bytes;Lnetwork/loki/messenger/libsession_util/util/Bytes;JJJ)V"); - return env->NewObject(legacy_group_class.get(), constructor, account_id.get(), name.get(), members.get(), enc_pubkey, enc_seckey, priority, (jlong) info.disappearing_timer.count(), joined_at); -} - -inline jobject serialize_closed_group_info(JNIEnv* env, session::config::group_info info) { - auto session_id = util::jstringFromOptional(env, info.id); - auto admin_bytes = jni_utils::JavaLocalRef(env, info.secretkey.empty() ? nullptr : jni_utils::session_bytes_from_range(env, info.secretkey)); - auto auth_bytes = jni_utils::JavaLocalRef(env, info.auth_data.empty() ? nullptr : jni_utils::session_bytes_from_range(env, info.auth_data)); - auto name = jni_utils::JavaLocalRef(env, util::jstringFromOptional(env, info.name)); - - auto group_info_class = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$ClosedGroupInfo")); - jmethodID constructor = env->GetMethodID(group_info_class.get(), "","(Ljava/lang/String;Lnetwork/loki/messenger/libsession_util/util/Bytes;Lnetwork/loki/messenger/libsession_util/util/Bytes;JZLjava/lang/String;ZZJ)V"); - return env->NewObject(group_info_class.get(), constructor, - session_id, admin_bytes.get(), auth_bytes.get(), (jlong)info.priority, info.invited, name.get(), - info.kicked(), info.is_destroyed(), info.joined_at); -} - -inline session::config::group_info deserialize_closed_group_info(JNIEnv* env, jobject info_serialized) { - auto closed_group_class = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$ClosedGroupInfo")); - jfieldID id_field = env->GetFieldID(closed_group_class.get(), "groupAccountId", "Ljava/lang/String;"); - auto secret_method = env->GetMethodID(closed_group_class.get(), "getAdminKeyAsByteArray", "()[B"); - auto auth_method = env->GetMethodID(closed_group_class.get(), "getAuthDataAsByteArray", "()[B"); - jfieldID priority_field = env->GetFieldID(closed_group_class.get(), "priority", "J"); - jfieldID invited_field = env->GetFieldID(closed_group_class.get(), "invited", "Z"); - jfieldID name_field = env->GetFieldID(closed_group_class.get(), "name", "Ljava/lang/String;"); - jfieldID destroy_field = env->GetFieldID(closed_group_class.get(), "destroyed", "Z"); - jfieldID kicked_field = env->GetFieldID(closed_group_class.get(), "kicked", "Z"); - jfieldID joined_at_field = env->GetFieldID(closed_group_class.get(), "joinedAtSecs", "J"); - - - auto id_jobject = jni_utils::JavaLocalRef(env, static_cast(env->GetObjectField(info_serialized, id_field))); - auto secret_jBytes = jni_utils::JavaLocalRef(env, (jbyteArray)env->CallObjectMethod(info_serialized, secret_method)); - auto auth_jBytes = jni_utils::JavaLocalRef(env, (jbyteArray)env->CallObjectMethod(info_serialized, auth_method)); - auto name_jstring = jni_utils::JavaLocalRef(env, (jstring)env->GetObjectField(info_serialized, name_field)); - - auto secret_bytes = util::vector_from_bytes(env, secret_jBytes.get()); - auto auth_bytes = util::vector_from_bytes(env, auth_jBytes.get()); - - session::config::group_info group_info(jni_utils::JavaStringRef(env, id_jobject.get()).copy()); - group_info.auth_data = auth_bytes; - group_info.secretkey = secret_bytes; - group_info.priority = env->GetLongField(info_serialized, priority_field); - group_info.invited = env->GetBooleanField(info_serialized, invited_field); - group_info.name = jni_utils::JavaStringRef(env, name_jstring.get()).view(); - group_info.joined_at = env->GetLongField(info_serialized, joined_at_field); - - if (env->GetBooleanField(info_serialized, kicked_field)) { - group_info.mark_kicked(); - } - - if (env->GetBooleanField(info_serialized, destroy_field)) { - group_info.mark_destroyed(); - } - - return group_info; -} - -inline jobject serialize_community_info(JNIEnv *env, session::config::community_info info) { - auto priority = (long long)info.priority; - auto serialized_info = util::serialize_base_community(env, info); - auto clazz = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$CommunityGroupInfo")); - jmethodID constructor = env->GetMethodID(clazz.get(), "", "(Lnetwork/loki/messenger/libsession_util/util/BaseCommunityInfo;J)V"); - jobject serialized = env->NewObject(clazz.get(), constructor, serialized_info, priority); - return serialized; -} +jni_utils::JavaLocalRef serialize_base_community(JNIEnv *env, const session::config::community& base_community); +session::config::community deserialize_base_community(JNIEnv *env, jobject base_community); #endif //SESSION_ANDROID_USER_GROUPS_H diff --git a/library/src/main/cpp/user_profile.cpp b/library/src/main/cpp/user_profile.cpp index e7f15ee..6fa8c55 100644 --- a/library/src/main/cpp/user_profile.cpp +++ b/library/src/main/cpp/user_profile.cpp @@ -17,18 +17,14 @@ Java_network_loki_messenger_libsession_1util_UserProfile_getName(JNIEnv *env, jo auto profile = ptrToProfile(env, thiz); auto name = profile->get_name(); if (name == std::nullopt) return nullptr; - jstring returnString = env->NewStringUTF(name->data()); - return returnString; + return env->NewStringUTF(name->data()); } JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_UserProfile_getPic(JNIEnv *env, jobject thiz) { auto profile = ptrToProfile(env, thiz); auto pic = profile->get_profile_pic(); - - jobject returnObject = util::serialize_user_pic(env, pic); - - return returnObject; + return util::serialize_user_pic(env, pic).leak(); } JNIEXPORT void JNICALL @@ -69,11 +65,11 @@ Java_network_loki_messenger_libsession_1util_UserProfile_getNtsExpiry(JNIEnv *en if (nts_expiry == std::nullopt) { auto expiry = util::serialize_expiry(env, session::config::expiration_mode::none, std::chrono::seconds(0)); - return expiry; + return expiry.leak(); } auto expiry = util::serialize_expiry(env, session::config::expiration_mode::after_send, std::chrono::seconds(*nts_expiry)); - return expiry; + return expiry.leak(); } extern "C" @@ -199,7 +195,7 @@ Java_network_loki_messenger_libsession_1util_UserProfile_getProConfig(JNIEnv *en return env->NewObject(clazz, constructor, cpp_to_java_proof(env, profile->proof), - util::bytes_from_span(env, profile->rotating_privkey) + util::bytes_from_span(env, profile->rotating_privkey).get() ); } diff --git a/library/src/main/cpp/util.cpp b/library/src/main/cpp/util.cpp index a99440b..eb41815 100644 --- a/library/src/main/cpp/util.cpp +++ b/library/src/main/cpp/util.cpp @@ -5,6 +5,7 @@ #include #include #include "jni_utils.h" +#include "user_groups.h" #include @@ -17,14 +18,16 @@ #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) +using namespace jni_utils; + namespace util { - jbyteArray bytes_from_vector(JNIEnv* env, const std::vector &from_str) { + JavaLocalRef bytes_from_vector(JNIEnv* env, const std::vector &from_str) { size_t length = from_str.size(); auto jlength = (jsize)length; jbyteArray new_array = env->NewByteArray(jlength); env->SetByteArrayRegion(new_array, 0, jlength, (jbyte*)from_str.data()); - return new_array; + return {env, new_array}; } std::vector vector_from_bytes(JNIEnv* env, jbyteArray byteArray) { @@ -35,21 +38,21 @@ namespace util { return jni_utils::JavaByteArrayRef(env, byteArray).copy(); } - jbyteArray bytes_from_span(JNIEnv* env, std::span from_str) { + JavaLocalRef bytes_from_span(JNIEnv* env, std::span from_str) { size_t length = from_str.size(); auto jlength = (jsize)length; jbyteArray new_array = env->NewByteArray(jlength); env->SetByteArrayRegion(new_array, 0, jlength, (jbyte*)from_str.data()); - return new_array; + return {env, new_array}; } - jobject serialize_user_pic(JNIEnv *env, session::config::profile_pic pic) { + JavaLocalRef serialize_user_pic(JNIEnv *env, session::config::profile_pic pic) { jni_utils::JavaLocalRef returnObjectClass(env, env->FindClass("network/loki/messenger/libsession_util/util/UserPic")); jmethodID constructor = env->GetMethodID(returnObjectClass.get(), "", "(Ljava/lang/String;Lnetwork/loki/messenger/libsession_util/util/Bytes;)V"); - return env->NewObject(returnObjectClass.get(), constructor, + return {env, env->NewObject(returnObjectClass.get(), constructor, jni_utils::JavaLocalRef(env, env->NewStringUTF(pic.url.data())).get(), - jni_utils::session_bytes_from_range(env, pic.key) - ); + jni_utils::session_bytes_from_range(env, pic.key).get() + )}; } @@ -61,32 +64,7 @@ namespace util { }; } - jobject serialize_base_community(JNIEnv *env, const session::config::community& community) { - auto base_community_clazz = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/BaseCommunityInfo")); - jmethodID base_community_constructor = env->GetMethodID(base_community_clazz.get(), "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); - auto base_url = jni_utils::JavaLocalRef(env, env->NewStringUTF(community.base_url().data())); - auto room = jni_utils::JavaLocalRef(env, env->NewStringUTF(community.room().data())); - auto pubkey_jstring = jni_utils::JavaLocalRef(env, env->NewStringUTF(community.pubkey_hex().data())); - return env->NewObject(base_community_clazz.get(), base_community_constructor, base_url.get(), room.get(), pubkey_jstring.get()); - } - - session::config::community deserialize_base_community(JNIEnv *env, jobject base_community) { - jclass base_community_clazz = env->FindClass("network/loki/messenger/libsession_util/util/BaseCommunityInfo"); - jfieldID base_url_field = env->GetFieldID(base_community_clazz, "baseUrl", "Ljava/lang/String;"); - jfieldID room_field = env->GetFieldID(base_community_clazz, "room", "Ljava/lang/String;"); - jfieldID pubkey_hex_field = env->GetFieldID(base_community_clazz, "pubKeyHex", "Ljava/lang/String;"); - jni_utils::JavaLocalRef base_url(env, (jstring)env->GetObjectField(base_community,base_url_field)); - jni_utils::JavaLocalRef room(env, (jstring)env->GetObjectField(base_community, room_field)); - jni_utils::JavaLocalRef pub_key_hex(env, (jstring)env->GetObjectField(base_community, pubkey_hex_field)); - - return session::config::community( - jni_utils::JavaStringRef(env, base_url.get()).view(), - jni_utils::JavaStringRef(env, room.get()).view(), - jni_utils::JavaStringRef(env, pub_key_hex.get()).view() - ); - } - - jobject serialize_expiry(JNIEnv *env, const session::config::expiration_mode& mode, const std::chrono::seconds& time_seconds) { + JavaLocalRef serialize_expiry(JNIEnv *env, const session::config::expiration_mode& mode, const std::chrono::seconds& time_seconds) { auto none = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$NONE")); jfieldID none_instance = env->GetStaticFieldID(none.get(), "INSTANCE", "Lnetwork/loki/messenger/libsession_util/util/ExpiryMode$NONE;"); auto after_send = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$AfterSend")); @@ -95,13 +73,13 @@ namespace util { jmethodID read_init = env->GetMethodID(after_read.get(), "", "(J)V"); if (mode == session::config::expiration_mode::none) { - return env->GetStaticObjectField(none.get(), none_instance); + return {env, env->GetStaticObjectField(none.get(), none_instance)}; } else if (mode == session::config::expiration_mode::after_send) { - return env->NewObject(after_send.get(), send_init, time_seconds.count()); + return {env, env->NewObject(after_send.get(), send_init, time_seconds.count())}; } else if (mode == session::config::expiration_mode::after_read) { - return env->NewObject(after_read.get(), read_init, time_seconds.count()); + return {env, env->NewObject(after_read.get(), read_init, time_seconds.count())}; } - return nullptr; + return {env, nullptr}; } std::pair deserialize_expiry(JNIEnv *env, jobject expiry_mode) { @@ -120,39 +98,15 @@ namespace util { return std::pair(session::config::expiration_mode::none, 0); } - jobject serialize_group_member(JNIEnv* env, const session::config::groups::member& member) { - auto group_member_class = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/GroupMember")); - jmethodID constructor = env->GetMethodID(group_member_class.get(), "", "(J)V"); - return env->NewObject(group_member_class.get(), - constructor, - reinterpret_cast(new session::config::groups::member(member)) - ); - } - - jobject deserialize_swarm_auth(JNIEnv *env, session::config::groups::Keys::swarm_auth auth) { - auto swarm_auth_class = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/GroupKeysConfig$SwarmAuth")); - jmethodID constructor = env->GetMethodID(swarm_auth_class.get(), "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); - auto sub_account = jni_utils::JavaLocalRef(env, env->NewStringUTF(auth.subaccount.data())); - auto sub_account_sig = jni_utils::JavaLocalRef(env, env->NewStringUTF(auth.subaccount_sig.data())); - auto signature = jni_utils::JavaLocalRef(env, env->NewStringUTF(auth.signature.data())); - return env->NewObject(swarm_auth_class.get(), constructor, sub_account.get(), sub_account_sig.get(), signature.get()); - } - jobject jlongFromOptional(JNIEnv* env, std::optional optional) { + JavaLocalRef jlongFromOptional(JNIEnv* env, std::optional optional) { if (!optional) { - return nullptr; + return {env, nullptr}; } auto longClass = jni_utils::JavaLocalRef(env, env->FindClass("java/lang/Long")); jmethodID constructor = env->GetMethodID(longClass.get(), "", "(J)V"); - return env->NewObject(longClass.get(), constructor, (jlong)*optional); - } - - jstring jstringFromOptional(JNIEnv* env, std::optional optional) { - if (!optional) { - return nullptr; - } - return env->NewStringUTF(optional->data()); + return {env, env->NewObject(longClass.get(), constructor, (jlong)*optional)}; } } @@ -196,8 +150,7 @@ Java_network_loki_messenger_libsession_1util_util_MultiEncrypt_encryptForMultipl std::span {random_nonce.data(), 24} ); - auto encoded = util::bytes_from_vector(env, result); - return encoded; + return util::bytes_from_vector(env, result).leak(); } extern "C" @@ -216,7 +169,7 @@ Java_network_loki_messenger_libsession_1util_util_MultiEncrypt_decryptForMultipl ); if (result) { - return util::bytes_from_vector(env, *result); + return util::bytes_from_vector(env, *result).leak(); } else { LOGD("no result from decrypt"); } @@ -236,14 +189,14 @@ Java_network_loki_messenger_libsession_1util_util_BaseCommunityInfo_00024Compani auto room_j = env->NewStringUTF(room.data()); auto pk_jbytes = util::bytes_from_vector(env, pk); - jobject triple = env->NewObject(clazz, constructor, base_j, room_j, pk_jbytes); + jobject triple = env->NewObject(clazz, constructor, base_j, room_j, pk_jbytes.get()); return triple; } extern "C" JNIEXPORT jstring JNICALL Java_network_loki_messenger_libsession_1util_util_BaseCommunityInfo_fullUrl(JNIEnv *env, jobject thiz) { - auto deserialized = util::deserialize_base_community(env, thiz); + auto deserialized = deserialize_base_community(env, thiz); auto full_url = deserialized.full_url(); return env->NewStringUTF(full_url.data()); } diff --git a/library/src/main/cpp/util.h b/library/src/main/cpp/util.h index 6725ecd..5243906 100644 --- a/library/src/main/cpp/util.h +++ b/library/src/main/cpp/util.h @@ -15,20 +15,19 @@ #include "session/config/user_groups.hpp" #include "session/config/expiring.hpp" +#include "jni_utils.h" + namespace util { - jbyteArray bytes_from_vector(JNIEnv* env, const std::vector &from_str); + jni_utils::JavaLocalRef bytes_from_vector(JNIEnv* env, const std::vector &from_str); std::vector vector_from_bytes(JNIEnv* env, jbyteArray byteArray); - jbyteArray bytes_from_span(JNIEnv* env, std::span from_str); - jobject serialize_user_pic(JNIEnv *env, session::config::profile_pic pic); + jni_utils::JavaLocalRef bytes_from_span(JNIEnv* env, std::span from_str); + jni_utils::JavaLocalRef serialize_user_pic(JNIEnv *env, session::config::profile_pic pic); session::config::profile_pic deserialize_user_pic(JNIEnv *env, jobject user_pic); - jobject serialize_base_community(JNIEnv *env, const session::config::community& base_community); - session::config::community deserialize_base_community(JNIEnv *env, jobject base_community); - jobject serialize_expiry(JNIEnv *env, const session::config::expiration_mode& mode, const std::chrono::seconds& time_seconds); + + jni_utils::JavaLocalRef serialize_expiry(JNIEnv *env, const session::config::expiration_mode& mode, const std::chrono::seconds& time_seconds); std::pair deserialize_expiry(JNIEnv *env, jobject expiry_mode); - jobject serialize_group_member(JNIEnv* env, const session::config::groups::member& member); - jobject jlongFromOptional(JNIEnv* env, std::optional optional); - jstring jstringFromOptional(JNIEnv* env, std::optional optional); - jobject deserialize_swarm_auth(JNIEnv *env, session::config::groups::Keys::swarm_auth auth); + + jni_utils::JavaLocalRef jlongFromOptional(JNIEnv* env, std::optional optional); } #endif \ No newline at end of file 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 57dc19c..7bcedd2 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 @@ -1,6 +1,7 @@ package network.loki.messenger.libsession_util import network.loki.messenger.libsession_util.pro.ProConfig +import network.loki.messenger.libsession_util.pro.ProProof import network.loki.messenger.libsession_util.protocol.ProFeatures import network.loki.messenger.libsession_util.util.BaseCommunityInfo import network.loki.messenger.libsession_util.util.BlindedContact @@ -11,6 +12,7 @@ import network.loki.messenger.libsession_util.util.ExpiryMode import network.loki.messenger.libsession_util.util.GroupInfo import network.loki.messenger.libsession_util.util.GroupMember import network.loki.messenger.libsession_util.util.UserPic +import java.time.Instant typealias ConversationPriority = Long @@ -114,6 +116,9 @@ interface MutableUserProfile : ReadableUserProfile, MutableConfig { interface ReadableConversationVolatileConfig: ReadableConfig { fun getOneToOne(pubKeyHex: String): Conversation.OneToOne? + + fun getBlindedOneToOne(pubKeyHex: String): Conversation.BlindedOneToOne? + fun getCommunity(baseUrl: String, room: String): Conversation.Community? fun getLegacyClosedGroup(groupId: String): Conversation.LegacyGroup? fun getClosedGroup(sessionId: String): Conversation.ClosedGroup? @@ -125,6 +130,7 @@ interface ReadableConversationVolatileConfig: ReadableConfig { fun empty(): Boolean fun allOneToOnes(): List + fun allBlindedOneToOnes(): List fun allCommunities(): List fun allLegacyClosedGroups(): List fun allClosedGroups(): List diff --git a/library/src/main/java/network/loki/messenger/libsession_util/ConversationVolatileConfig.kt b/library/src/main/java/network/loki/messenger/libsession_util/ConversationVolatileConfig.kt index e3e4c5d..60cd109 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/ConversationVolatileConfig.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/ConversationVolatileConfig.kt @@ -39,6 +39,9 @@ class ConversationVolatileConfig private constructor(pointer: Long): ConfigBase( external override fun getOrConstructedBlindedOneToOne(blindedId: String): Conversation.BlindedOneToOne external override fun eraseBlindedOneToOne(blindedId: String): Boolean + external override fun getBlindedOneToOne(pubKeyHex: String): Conversation.BlindedOneToOne? + external override fun allBlindedOneToOnes(): List + override fun set(conv: Conversation) { when (conv) { is Conversation.BlindedOneToOne -> setBlindedOneToOne(conv) diff --git a/library/src/main/java/network/loki/messenger/libsession_util/util/Conversation.kt b/library/src/main/java/network/loki/messenger/libsession_util/util/Conversation.kt index d7e2ca3..b42e692 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/util/Conversation.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/util/Conversation.kt @@ -1,37 +1,67 @@ package network.loki.messenger.libsession_util.util -sealed class Conversation { +import androidx.annotation.Keep +import java.time.Instant - abstract var lastRead: Long - abstract var unread: Boolean +sealed interface Conversation { + + var lastRead: Long + var unread: Boolean + + /** + * The minimal information about a Pro Proof stored in a Conversation. + * This is not a full ProProof, it contains just enough for the clients to check it it's revoked. + */ + data class ProProofInfo( + val genIndexHash: Bytes, + val expiry: Instant, + ) { + @Keep + constructor( + genIndexHash: ByteArray, + expiryMs: Long, + ) : this( + genIndexHash = Bytes(genIndexHash), + expiry = Instant.ofEpochMilli(expiryMs) + ) + } + + /** + * A Conversation that contains Pro information. + */ + sealed interface WithProProofInfo : Conversation { + var proProofInfo: ProProofInfo? + } data class OneToOne( val accountId: String, override var lastRead: Long, - override var unread: Boolean - ): Conversation() + override var unread: Boolean, + override var proProofInfo: ProProofInfo?, + ): Conversation, WithProProofInfo data class Community( val baseCommunityInfo: BaseCommunityInfo, override var lastRead: Long, override var unread: Boolean - ) : Conversation() + ) : Conversation data class LegacyGroup( val groupId: String, override var lastRead: Long, override var unread: Boolean - ): Conversation() + ): Conversation data class ClosedGroup( val accountId: String, override var lastRead: Long, override var unread: Boolean - ): Conversation() + ): Conversation data class BlindedOneToOne( val blindedAccountId: String, override var lastRead: Long, - override var unread: Boolean - ) : Conversation() + override var unread: Boolean, + override var proProofInfo: ProProofInfo?, + ) : Conversation, WithProProofInfo } \ No newline at end of file From 7b447d3b9d21958f8b4ee129d91bf9251d32ee73 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Mon, 24 Nov 2025 15:53:04 +1100 Subject: [PATCH 21/26] Tidy up --- library/src/main/cpp/config_base.cpp | 34 ++++++- library/src/main/cpp/config_base.h | 21 +---- library/src/main/cpp/conversation.cpp | 8 +- library/src/main/cpp/conversation.h | 17 ---- library/src/main/cpp/group_info.cpp | 12 ++- library/src/main/cpp/group_info.h | 13 --- library/src/main/cpp/group_keys.cpp | 11 ++- library/src/main/cpp/group_keys.h | 13 --- library/src/main/cpp/group_members.cpp | 12 ++- library/src/main/cpp/group_members.h | 10 +-- library/src/main/cpp/pro_backend.cpp | 12 ++- library/src/main/cpp/pro_proof_util.cpp | 29 +++--- library/src/main/cpp/protocol.cpp | 14 +-- library/src/main/cpp/user_groups.cpp | 115 ++++++++++++++++-------- library/src/main/cpp/user_groups.h | 5 +- library/src/main/cpp/user_profile.cpp | 19 ++-- library/src/main/cpp/user_profile.h | 16 ---- library/src/main/cpp/util.cpp | 41 +++++---- 18 files changed, 222 insertions(+), 180 deletions(-) delete mode 100644 library/src/main/cpp/conversation.h delete mode 100644 library/src/main/cpp/group_info.h delete mode 100644 library/src/main/cpp/group_keys.h delete mode 100644 library/src/main/cpp/user_profile.h diff --git a/library/src/main/cpp/config_base.cpp b/library/src/main/cpp/config_base.cpp index 013eb06..44448c2 100644 --- a/library/src/main/cpp/config_base.cpp +++ b/library/src/main/cpp/config_base.cpp @@ -16,6 +16,29 @@ std::pair> extractHashAndData(JNIEnv *en ); } +struct JavaConfigClassInfo : public jni_utils::JavaClassInfo { + jfieldID pointer_field; + + JavaConfigClassInfo(JNIEnv *env, jobject obj) + :JavaClassInfo(env, obj), + pointer_field(env->GetFieldID(java_class, "pointer", "J")) {} + + static const JavaConfigClassInfo& get(JNIEnv *env, jobject obj) { + static JavaConfigClassInfo class_info(env, obj); + return class_info; + } +}; + +session::config::ConfigBase* ptrToConfigBase(JNIEnv *env, jobject obj) { + return reinterpret_cast( + env->GetLongField(obj, JavaConfigClassInfo::get(env, obj).pointer_field)); +} + +session::config::ConfigSig* ptrToConfigSig(JNIEnv* env, jobject obj) { + return reinterpret_cast( + env->GetLongField(obj, JavaConfigClassInfo::get(env, obj).pointer_field)); +} + extern "C" { JNIEXPORT jboolean JNICALL Java_network_loki_messenger_libsession_1util_ConfigBase_dirty(JNIEnv *env, jobject thiz) { @@ -47,9 +70,14 @@ Java_network_loki_messenger_libsession_1util_ConfigBase_push(JNIEnv *env, jobjec jobject obsoleteHashes = jni_utils::jstring_list_from_collection(env, to_delete); - jclass returnObjectClass = env->FindClass("network/loki/messenger/libsession_util/util/ConfigPush"); - jmethodID methodId = env->GetMethodID(returnObjectClass, "", "(Ljava/util/List;JLjava/util/List;)V"); - return env->NewObject(returnObjectClass, methodId, messages, static_cast(seq_no), obsoleteHashes); + static jni_utils::BasicJavaClassInfo class_info( + env, + "network/loki/messenger/libsession_util/util/ConfigPush", + "(Ljava/util/List;JLjava/util/List;)V" + ); + + return env->NewObject(class_info.java_class, class_info.constructor, + messages, static_cast(seq_no), obsoleteHashes); }); } diff --git a/library/src/main/cpp/config_base.h b/library/src/main/cpp/config_base.h index d42353c..5fec845 100644 --- a/library/src/main/cpp/config_base.h +++ b/library/src/main/cpp/config_base.h @@ -1,24 +1,11 @@ #ifndef SESSION_ANDROID_CONFIG_BASE_H #define SESSION_ANDROID_CONFIG_BASE_H -#include "session/config/base.hpp" -#include "util.h" -#include "jni_utils.h" -#include -#include -#include - -inline session::config::ConfigBase* ptrToConfigBase(JNIEnv *env, jobject obj) { - auto baseClass = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/ConfigBase")); - jfieldID pointerField = env->GetFieldID(baseClass.get(), "pointer", "J"); - return (session::config::ConfigBase*) env->GetLongField(obj, pointerField); -} +#include +#include -inline session::config::ConfigSig* ptrToConfigSig(JNIEnv* env, jobject obj) { - auto sigClass = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/ConfigSig")); - jfieldID pointerField = env->GetFieldID(sigClass.get(), "pointer", "J"); - return (session::config::ConfigSig*) env->GetLongField(obj, pointerField); -} +session::config::ConfigBase* ptrToConfigBase(JNIEnv *env, jobject obj); +session::config::ConfigSig* ptrToConfigSig(JNIEnv* env, jobject obj); #endif \ No newline at end of file diff --git a/library/src/main/cpp/conversation.cpp b/library/src/main/cpp/conversation.cpp index 48f2a42..311e05c 100644 --- a/library/src/main/cpp/conversation.cpp +++ b/library/src/main/cpp/conversation.cpp @@ -1,10 +1,16 @@ #include -#include "conversation.h" +#include + #include "jni_utils.h" +#include "util.h" #include "user_groups.h" +#include "config_base.h" using namespace jni_utils; +static auto ptrToConvoInfo(JNIEnv *env, jobject obj) { + return dynamic_cast(ptrToConfigBase(env, obj)); +} JavaLocalRef serialize_pro_proof_info(JNIEnv *env, std::optional> gen_index_hash, diff --git a/library/src/main/cpp/conversation.h b/library/src/main/cpp/conversation.h deleted file mode 100644 index 0d784b7..0000000 --- a/library/src/main/cpp/conversation.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef SESSION_ANDROID_CONVERSATION_H -#define SESSION_ANDROID_CONVERSATION_H - -#include -#include -#include "util.h" -#include "session/config/convo_info_volatile.hpp" -#include "jni_utils.h" - -inline session::config::ConvoInfoVolatile *ptrToConvoInfo(JNIEnv *env, jobject obj) { - auto contactsClass = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/ConversationVolatileConfig")); - jfieldID pointerField = env->GetFieldID(contactsClass.get(), "pointer", "J"); - return (session::config::ConvoInfoVolatile *) env->GetLongField(obj, pointerField); -} - - -#endif //SESSION_ANDROID_CONVERSATION_H \ No newline at end of file diff --git a/library/src/main/cpp/group_info.cpp b/library/src/main/cpp/group_info.cpp index 6986658..464688e 100644 --- a/library/src/main/cpp/group_info.cpp +++ b/library/src/main/cpp/group_info.cpp @@ -1,6 +1,14 @@ +#include #include -#include "group_info.h" -#include "session/config/groups/info.hpp" + +#include "util.h" +#include "jni_utils.h" +#include "config_base.h" + +inline auto ptrToInfo(JNIEnv* env, jobject obj) { + return dynamic_cast(ptrToConfigBase(env, obj)); +} + extern "C" JNIEXPORT jlong JNICALL diff --git a/library/src/main/cpp/group_info.h b/library/src/main/cpp/group_info.h deleted file mode 100644 index ab48243..0000000 --- a/library/src/main/cpp/group_info.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef SESSION_ANDROID_GROUP_INFO_H -#define SESSION_ANDROID_GROUP_INFO_H - -#include "util.h" -#include "jni_utils.h" - -inline session::config::groups::Info* ptrToInfo(JNIEnv* env, jobject obj) { - auto configClass = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/GroupInfoConfig")); - jfieldID pointerField = env->GetFieldID(configClass.get(), "pointer", "J"); - return (session::config::groups::Info*) env->GetLongField(obj, pointerField); -} - -#endif //SESSION_ANDROID_GROUP_INFO_H diff --git a/library/src/main/cpp/group_keys.cpp b/library/src/main/cpp/group_keys.cpp index 28ddd81..bace503 100644 --- a/library/src/main/cpp/group_keys.cpp +++ b/library/src/main/cpp/group_keys.cpp @@ -1,8 +1,13 @@ -#include "group_keys.h" -#include "group_info.h" -#include "group_members.h" +#include +#include "group_members.h" #include "jni_utils.h" +#include "util.h" +#include "config_base.h" + +inline auto ptrToKeys(JNIEnv* env, jobject obj) { + return dynamic_cast(ptrToConfigSig(env, obj)); +} extern "C" JNIEXPORT jint JNICALL diff --git a/library/src/main/cpp/group_keys.h b/library/src/main/cpp/group_keys.h deleted file mode 100644 index 73c41ea..0000000 --- a/library/src/main/cpp/group_keys.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef SESSION_ANDROID_GROUP_KEYS_H -#define SESSION_ANDROID_GROUP_KEYS_H - -#include "util.h" -#include "jni_utils.h" - -inline session::config::groups::Keys* ptrToKeys(JNIEnv* env, jobject obj) { - auto configClass = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/GroupKeysConfig")); - jfieldID pointerField = env->GetFieldID(configClass.get(), "pointer", "J"); - return (session::config::groups::Keys*) env->GetLongField(obj, pointerField); -} - -#endif //SESSION_ANDROID_GROUP_KEYS_H diff --git a/library/src/main/cpp/group_members.cpp b/library/src/main/cpp/group_members.cpp index b5a4e13..d1531af 100644 --- a/library/src/main/cpp/group_members.cpp +++ b/library/src/main/cpp/group_members.cpp @@ -1,9 +1,19 @@ #include "group_members.h" - #include "jni_utils.h" +#include "util.h" +#include "config_base.h" using namespace jni_utils; +inline session::config::groups::Members* ptrToMembers(JNIEnv* env, jobject obj) { + return dynamic_cast(ptrToConfigBase(env, obj)); +} + +inline session::config::groups::member *ptrToMember(JNIEnv *env, jobject thiz) { + auto ptrField = env->GetFieldID(jni_utils::JavaLocalRef(env, env->GetObjectClass(thiz)).get(), "nativePtr", "J"); + return reinterpret_cast(env->GetLongField(thiz, ptrField)); +} + extern "C" JNIEXPORT jlong JNICALL Java_network_loki_messenger_libsession_1util_GroupMembersConfig_00024Companion_newInstance( diff --git a/library/src/main/cpp/group_members.h b/library/src/main/cpp/group_members.h index 91a7bbd..3ef9a51 100644 --- a/library/src/main/cpp/group_members.h +++ b/library/src/main/cpp/group_members.h @@ -1,18 +1,10 @@ #ifndef SESSION_ANDROID_GROUP_MEMBERS_H #define SESSION_ANDROID_GROUP_MEMBERS_H -#include "util.h" #include "jni_utils.h" -inline session::config::groups::Members* ptrToMembers(JNIEnv* env, jobject obj) { - jfieldID pointerField = env->GetFieldID(jni_utils::JavaLocalRef(env, env->GetObjectClass(obj)).get(), "pointer", "J"); - return (session::config::groups::Members*) env->GetLongField(obj, pointerField); -} +#include -inline session::config::groups::member *ptrToMember(JNIEnv *env, jobject thiz) { - auto ptrField = env->GetFieldID(jni_utils::JavaLocalRef(env, env->GetObjectClass(thiz)).get(), "nativePtr", "J"); - return reinterpret_cast(env->GetLongField(thiz, ptrField)); -} jni_utils::JavaLocalRef serialize_group_member(JNIEnv* env, const session::config::groups::member& member); diff --git a/library/src/main/cpp/pro_backend.cpp b/library/src/main/cpp/pro_backend.cpp index a5ed5a3..5cc0588 100644 --- a/library/src/main/cpp/pro_backend.cpp +++ b/library/src/main/cpp/pro_backend.cpp @@ -73,10 +73,16 @@ Java_network_loki_messenger_libsession_1util_pro_BackendRequests_getPaymentProvi } const auto & metadata = SESSION_PRO_BACKEND_PAYMENT_PROVIDER_METADATA[payment_provider]; - auto clazz = env->FindClass("network/loki/messenger/libsession_util/protocol/PaymentProviderMetadata"); + + static BasicJavaClassInfo class_info( + env, + "network/loki/messenger/libsession_util/protocol/PaymentProviderMetadata", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + + return env->NewObject( - clazz, - env->GetMethodID(clazz, "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"), + class_info.java_class, + class_info.constructor, jni_utils::jstring_from_optional(env, std::string_view(metadata.device.data, metadata.device.size)).get(), jni_utils::jstring_from_optional(env, std::string_view(metadata.store.data, metadata.store.size)).get(), jni_utils::jstring_from_optional(env, std::string_view(metadata.platform.data, metadata.platform.size)).get(), diff --git a/library/src/main/cpp/pro_proof_util.cpp b/library/src/main/cpp/pro_proof_util.cpp index fdc9a5e..cdced32 100644 --- a/library/src/main/cpp/pro_proof_util.cpp +++ b/library/src/main/cpp/pro_proof_util.cpp @@ -18,24 +18,24 @@ static std::array from_hex(std::span input) { } session::ProProof java_to_cpp_proof(JNIEnv *env, jobject proof) { - struct ProProofMethods { + struct ProProofMethods : public JavaClassInfo { jmethodID get_version; jmethodID get_gen_index_hash; jmethodID get_rotating_pub_key; jmethodID get_expiry_ms; jmethodID get_signature; - ProProofMethods(JNIEnv *env, jclass clazz) { - get_version = env->GetMethodID(clazz, "getVersion", "()I"); - get_gen_index_hash = env->GetMethodID(clazz, "getGenIndexHashHex", "()Ljava/lang/String;"); - get_rotating_pub_key = env->GetMethodID(clazz, "getRotatingPubKeyHex", "()Ljava/lang/String;"); - get_expiry_ms = env->GetMethodID(clazz, "getExpiryMs", "()J"); - get_signature = env->GetMethodID(clazz, "getSignatureHex", "()Ljava/lang/String;"); - } + ProProofMethods(JNIEnv *env, jobject obj) + : JavaClassInfo(env, obj) + , get_version(env->GetMethodID(java_class, "getVersion", "()I")) + , get_gen_index_hash(env->GetMethodID(java_class, "getGenIndexHashHex", "()Ljava/lang/String;")) + , get_rotating_pub_key(env->GetMethodID(java_class, "getRotatingPubKeyHex", "()Ljava/lang/String;")) + , get_expiry_ms(env->GetMethodID(java_class, "getExpiryMs", "()J")) + , get_signature(env->GetMethodID(java_class, "getSignatureHex", "()Ljava/lang/String;")) {} }; // Cache method IDs - static ProProofMethods methods(env, jni_utils::JavaLocalRef(env, env->GetObjectClass(proof)).get()); + static ProProofMethods methods(env, proof); jni_utils::JavaLocalRef gen_index_hash(env, (jstring) env->CallObjectMethod(proof, methods.get_gen_index_hash)); jni_utils::JavaLocalRef rotating_pub_key(env, (jstring) env->CallObjectMethod(proof, methods.get_rotating_pub_key)); @@ -52,12 +52,13 @@ session::ProProof java_to_cpp_proof(JNIEnv *env, jobject proof) { } jobject cpp_to_java_proof(JNIEnv *env, const session::ProProof &proof) { - JavaLocalRef pro_proof_clazz(env, env->FindClass( - "network/loki/messenger/libsession_util/pro/ProProof")); - jmethodID init = env->GetMethodID(pro_proof_clazz.get(), "", "(I[B[BJ[B)V"); + static BasicJavaClassInfo class_info(env, + "network/loki/messenger/libsession_util/pro/ProProof", + "(I[B[BJ[B)V"); + return env->NewObject( - pro_proof_clazz.get(), - init, + class_info.java_class, + class_info.constructor, static_cast(proof.version), util::bytes_from_span(env, proof.gen_index_hash).get(), util::bytes_from_span(env, proof.rotating_pubkey).get(), diff --git a/library/src/main/cpp/protocol.cpp b/library/src/main/cpp/protocol.cpp index ac98d18..064c0a7 100644 --- a/library/src/main/cpp/protocol.cpp +++ b/library/src/main/cpp/protocol.cpp @@ -14,8 +14,7 @@ static JavaLocalRef serializeEnvelop(JNIEnv *env, const session::Envelo static BasicJavaClassInfo class_info( env, "network/loki/messenger/libsession_util/protocol/Envelope", - "(J[BJ[B)V" - ); + "(J[BJ[B)V"); return {env, env->NewObject(class_info.java_class, class_info.constructor, @@ -261,10 +260,15 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_proFeature static_cast(proposed_features) ); - auto clazz = env->FindClass("network/loki/messenger/libsession_util/protocol/ProFeaturesForMsg"); + static BasicJavaClassInfo class_info( + env, + "network/loki/messenger/libsession_util/protocol/ProFeaturesForMsg", + "(ILjava/lang/String;JI)V" + ); + return env->NewObject( - clazz, - env->GetMethodID(clazz, "", "(ILjava/lang/String;JI)V"), + class_info.java_class, + class_info.constructor, static_cast(features.status), features.error.empty() ? nullptr : env->NewStringUTF(std::string(features.error).c_str()), static_cast(features.features), diff --git a/library/src/main/cpp/user_groups.cpp b/library/src/main/cpp/user_groups.cpp index ab557ca..91b9f96 100644 --- a/library/src/main/cpp/user_groups.cpp +++ b/library/src/main/cpp/user_groups.cpp @@ -1,6 +1,6 @@ #include "user_groups.h" #include "oxenc/hex.h" - +#include "util.h" #include "session/ed25519.hpp" using namespace jni_utils; @@ -74,12 +74,20 @@ static session::config::legacy_group_info deserialize_legacy_group_info(JNIEnv * } static session::config::community_info deserialize_community_info(JNIEnv *env, jobject info, session::config::UserGroups* conf) { - auto clazz = JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$CommunityGroupInfo")); - auto base_info = env->GetFieldID(clazz.get(), "community", "Lnetwork/loki/messenger/libsession_util/util/BaseCommunityInfo;"); - auto priority = env->GetFieldID(clazz.get(), "priority", "J"); - auto base_community_info = JavaLocalRef(env, env->GetObjectField(info, base_info)); + struct ClassInfo : JavaClassInfo { + jmethodID base_info_getter; + jmethodID priority_getter; + + ClassInfo(JNIEnv *env): JavaClassInfo(env, "network/loki/messenger/libsession_util/util/GroupInfo$CommunityGroupInfo"), + base_info_getter(env->GetMethodID(java_class, "getCommunity", "()Lnetwork/loki/messenger/libsession_util/util/BaseCommunityInfo;")), + priority_getter(env->GetMethodID(java_class, "getPriority", "()J")) {} + }; + + static ClassInfo class_info(env); + + auto base_community_info = JavaLocalRef(env, env->CallObjectMethod(info, class_info.base_info_getter)); auto deserialized_base_info = deserialize_base_community(env, base_community_info.get()); - int deserialized_priority = env->GetLongField(info, priority); + int deserialized_priority = env->CallLongMethod(info, class_info.priority_getter); auto community_info = conf->get_or_construct_community(deserialized_base_info.base_url(), deserialized_base_info.room(), deserialized_base_info.pubkey_hex()); community_info.priority = deserialized_priority; return community_info; @@ -141,22 +149,37 @@ static JavaLocalRef serialize_closed_group_info(JNIEnv* env, session::c } static session::config::group_info deserialize_closed_group_info(JNIEnv* env, jobject info_serialized) { - auto closed_group_class = JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$ClosedGroupInfo")); - jfieldID id_field = env->GetFieldID(closed_group_class.get(), "groupAccountId", "Ljava/lang/String;"); - auto secret_method = env->GetMethodID(closed_group_class.get(), "getAdminKeyAsByteArray", "()[B"); - auto auth_method = env->GetMethodID(closed_group_class.get(), "getAuthDataAsByteArray", "()[B"); - jfieldID priority_field = env->GetFieldID(closed_group_class.get(), "priority", "J"); - jfieldID invited_field = env->GetFieldID(closed_group_class.get(), "invited", "Z"); - jfieldID name_field = env->GetFieldID(closed_group_class.get(), "name", "Ljava/lang/String;"); - jfieldID destroy_field = env->GetFieldID(closed_group_class.get(), "destroyed", "Z"); - jfieldID kicked_field = env->GetFieldID(closed_group_class.get(), "kicked", "Z"); - jfieldID joined_at_field = env->GetFieldID(closed_group_class.get(), "joinedAtSecs", "J"); - - - auto id_jobject = JavaLocalRef(env, static_cast(env->GetObjectField(info_serialized, id_field))); - auto secret_jBytes = JavaLocalRef(env, (jbyteArray)env->CallObjectMethod(info_serialized, secret_method)); - auto auth_jBytes = JavaLocalRef(env, (jbyteArray)env->CallObjectMethod(info_serialized, auth_method)); - auto name_jstring = JavaLocalRef(env, (jstring)env->GetObjectField(info_serialized, name_field)); + struct ClassInfo : public JavaClassInfo { + jmethodID id_getter; + jmethodID secret_method; + jmethodID auth_method; + jmethodID name_getter; + jmethodID priority_getter; + jmethodID invited_getter; + jmethodID destroyed_getter; + jmethodID kicked_getter; + jmethodID joined_at_getter; + + ClassInfo(JNIEnv *env, jobject obj) + : JavaClassInfo(env, obj) + , id_getter(env->GetMethodID(java_class, "getGroupAccountId", "()Ljava/lang/String;")) + , secret_method(env->GetMethodID(java_class, "getAdminKeyAsByteArray", "()[B")) + , auth_method(env->GetMethodID(java_class, "getAuthDataAsByteArray", "()[B")) + , name_getter(env->GetMethodID(java_class, "getName", "()Ljava/lang/String;")) + , priority_getter(env->GetMethodID(java_class, "getPriority", "()J")) + , invited_getter(env->GetMethodID(java_class, "getInvited", "()Z")) + , destroyed_getter(env->GetMethodID(java_class, "getDestroyed", "()Z")) + , kicked_getter(env->GetMethodID(java_class, "getKicked", "()Z")) + , joined_at_getter(env->GetMethodID(java_class, "getJoinedAtSecs", "()J")) + {} + }; + + static ClassInfo class_info(env, info_serialized); + + auto id_jobject = JavaLocalRef(env, static_cast(env->CallObjectMethod(info_serialized, class_info.id_getter))); + auto secret_jBytes = JavaLocalRef(env, (jbyteArray)env->CallObjectMethod(info_serialized, class_info.secret_method)); + auto auth_jBytes = JavaLocalRef(env, (jbyteArray)env->CallObjectMethod(info_serialized, class_info.auth_method)); + auto name_jstring = JavaLocalRef(env, (jstring)env->CallObjectMethod(info_serialized, class_info.name_getter)); auto secret_bytes = util::vector_from_bytes(env, secret_jBytes.get()); auto auth_bytes = util::vector_from_bytes(env, auth_jBytes.get()); @@ -164,23 +187,23 @@ static session::config::group_info deserialize_closed_group_info(JNIEnv* env, jo session::config::group_info group_info(JavaStringRef(env, id_jobject.get()).copy()); group_info.auth_data = auth_bytes; group_info.secretkey = secret_bytes; - group_info.priority = env->GetLongField(info_serialized, priority_field); - group_info.invited = env->GetBooleanField(info_serialized, invited_field); + group_info.priority = env->CallLongMethod(info_serialized, class_info.priority_getter); + group_info.invited = env->CallBooleanMethod(info_serialized, class_info.invited_getter); group_info.name = JavaStringRef(env, name_jstring.get()).view(); - group_info.joined_at = env->GetLongField(info_serialized, joined_at_field); + group_info.joined_at = env->CallLongMethod(info_serialized, class_info.joined_at_getter); - if (env->GetBooleanField(info_serialized, kicked_field)) { + if (env->CallBooleanMethod(info_serialized, class_info.kicked_getter)) { group_info.mark_kicked(); } - if (env->GetBooleanField(info_serialized, destroy_field)) { + if (env->CallBooleanMethod(info_serialized, class_info.destroyed_getter)) { group_info.mark_destroyed(); } return group_info; } -static JavaLocalRef serialize_community_info(JNIEnv *env, session::config::community_info info) { +static JavaLocalRef serialize_community_info(JNIEnv *env, const session::config::community_info &info) { auto priority = (long long)info.priority; auto serialized_info = serialize_base_community(env, info); @@ -194,22 +217,36 @@ static JavaLocalRef serialize_community_info(JNIEnv *env, session::conf } JavaLocalRef serialize_base_community(JNIEnv *env, const session::config::community& community) { - auto base_community_clazz = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/BaseCommunityInfo")); - jmethodID base_community_constructor = env->GetMethodID(base_community_clazz.get(), "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + static BasicJavaClassInfo class_info(env, "network/loki/messenger/libsession_util/util/BaseCommunityInfo", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + auto base_url = jni_utils::JavaLocalRef(env, env->NewStringUTF(community.base_url().data())); auto room = jni_utils::JavaLocalRef(env, env->NewStringUTF(community.room().data())); auto pubkey_jstring = jni_utils::JavaLocalRef(env, env->NewStringUTF(community.pubkey_hex().data())); - return {env, env->NewObject(base_community_clazz.get(), base_community_constructor, base_url.get(), room.get(), pubkey_jstring.get())}; + return {env, env->NewObject(class_info.java_class, + class_info.constructor, + base_url.get(), room.get(), pubkey_jstring.get())}; } session::config::community deserialize_base_community(JNIEnv *env, jobject base_community) { - jclass base_community_clazz = env->FindClass("network/loki/messenger/libsession_util/util/BaseCommunityInfo"); - jfieldID base_url_field = env->GetFieldID(base_community_clazz, "baseUrl", "Ljava/lang/String;"); - jfieldID room_field = env->GetFieldID(base_community_clazz, "room", "Ljava/lang/String;"); - jfieldID pubkey_hex_field = env->GetFieldID(base_community_clazz, "pubKeyHex", "Ljava/lang/String;"); - jni_utils::JavaLocalRef base_url(env, (jstring)env->GetObjectField(base_community,base_url_field)); - jni_utils::JavaLocalRef room(env, (jstring)env->GetObjectField(base_community, room_field)); - jni_utils::JavaLocalRef pub_key_hex(env, (jstring)env->GetObjectField(base_community, pubkey_hex_field)); + struct ClassInfo : public JavaClassInfo { + jmethodID base_url_getter; + jmethodID room_getter; + jmethodID pubkey_getter; + + ClassInfo(JNIEnv *env, jobject obj) + : JavaClassInfo(env, obj) + , base_url_getter(env->GetMethodID(java_class, "getBaseUrl", "()Ljava/lang/String;")) + , room_getter(env->GetMethodID(java_class, "getRoom", "()Ljava/lang/String;")) + , pubkey_getter(env->GetMethodID(java_class, "getPubKeyHex", "()Ljava/lang/String;")) + {} + }; + + static ClassInfo class_info(env, base_community); + + jni_utils::JavaLocalRef base_url(env, (jstring)env->CallObjectMethod(base_community, class_info.base_url_getter)); + jni_utils::JavaLocalRef room(env, (jstring)env->CallObjectMethod(base_community, class_info.room_getter)); + jni_utils::JavaLocalRef pub_key_hex(env, (jstring)env->CallObjectMethod(base_community, class_info.pubkey_getter)); return session::config::community( jni_utils::JavaStringRef(env, base_url.get()).view(), @@ -343,7 +380,7 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_sizeLegacyGroupInf extern "C" JNIEXPORT jlong JNICALL Java_network_loki_messenger_libsession_1util_UserGroupsConfig_size(JNIEnv *env, jobject thiz) { - auto conf = ptrToConvoInfo(env, thiz); + auto conf = ptrToUserGroups(env, thiz); return conf->size(); } diff --git a/library/src/main/cpp/user_groups.h b/library/src/main/cpp/user_groups.h index 95595d5..1a9f76d 100644 --- a/library/src/main/cpp/user_groups.h +++ b/library/src/main/cpp/user_groups.h @@ -2,11 +2,8 @@ #ifndef SESSION_ANDROID_USER_GROUPS_H #define SESSION_ANDROID_USER_GROUPS_H -#include "jni.h" -#include "util.h" #include "jni_utils.h" -#include "conversation.h" -#include "session/config/user_groups.hpp" +#include jni_utils::JavaLocalRef serialize_base_community(JNIEnv *env, const session::config::community& base_community); session::config::community deserialize_base_community(JNIEnv *env, jobject base_community); diff --git a/library/src/main/cpp/user_profile.cpp b/library/src/main/cpp/user_profile.cpp index 6fa8c55..ec4443f 100644 --- a/library/src/main/cpp/user_profile.cpp +++ b/library/src/main/cpp/user_profile.cpp @@ -1,6 +1,12 @@ -#include "user_profile.h" +#include + #include "util.h" #include "pro_proof_util.h" +#include "config_base.h" + +inline auto ptrToProfile(JNIEnv* env, jobject obj) { + return dynamic_cast(ptrToConfigBase(env, obj)); +} extern "C" { JNIEXPORT void JNICALL @@ -189,11 +195,14 @@ Java_network_loki_messenger_libsession_1util_UserProfile_getProConfig(JNIEnv *en return nullptr; } - auto clazz = env->FindClass("network/loki/messenger/libsession_util/pro/ProConfig"); - auto constructor = env->GetMethodID(clazz, "", "(Lnetwork/loki/messenger/libsession_util/pro/ProProof;[B)V"); + static jni_utils::BasicJavaClassInfo class_info( + env, + "network/loki/messenger/libsession_util/pro/ProConfig", + "(Lnetwork/loki/messenger/libsession_util/pro/ProProof;[B)V" + ); - return env->NewObject(clazz, - constructor, + return env->NewObject(class_info.java_class, + class_info.constructor, cpp_to_java_proof(env, profile->proof), util::bytes_from_span(env, profile->rotating_privkey).get() ); diff --git a/library/src/main/cpp/user_profile.h b/library/src/main/cpp/user_profile.h deleted file mode 100644 index 2b3f273..0000000 --- a/library/src/main/cpp/user_profile.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef SESSION_ANDROID_USER_PROFILE_H -#define SESSION_ANDROID_USER_PROFILE_H - -#include "session/config/user_profile.hpp" -#include -#include - -#include "jni_utils.h" - -inline session::config::UserProfile* ptrToProfile(JNIEnv* env, jobject obj) { - auto configClass = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/UserProfile")); - jfieldID pointerField = env->GetFieldID(configClass.get(), "pointer", "J"); - return (session::config::UserProfile*) env->GetLongField(obj, pointerField); -} - -#endif \ No newline at end of file diff --git a/library/src/main/cpp/util.cpp b/library/src/main/cpp/util.cpp index eb41815..5bfa8c2 100644 --- a/library/src/main/cpp/util.cpp +++ b/library/src/main/cpp/util.cpp @@ -47,9 +47,12 @@ namespace util { } JavaLocalRef serialize_user_pic(JNIEnv *env, session::config::profile_pic pic) { - jni_utils::JavaLocalRef returnObjectClass(env, env->FindClass("network/loki/messenger/libsession_util/util/UserPic")); - jmethodID constructor = env->GetMethodID(returnObjectClass.get(), "", "(Ljava/lang/String;Lnetwork/loki/messenger/libsession_util/util/Bytes;)V"); - return {env, env->NewObject(returnObjectClass.get(), constructor, + static jni_utils::BasicJavaClassInfo class_info( + env, "network/loki/messenger/libsession_util/util/UserPic", + "(Ljava/lang/String;Lnetwork/loki/messenger/libsession_util/util/Bytes;)V" + ); + + return {env, env->NewObject(class_info.java_class, class_info.constructor, jni_utils::JavaLocalRef(env, env->NewStringUTF(pic.url.data())).get(), jni_utils::session_bytes_from_range(env, pic.key).get() )}; @@ -65,19 +68,23 @@ namespace util { } JavaLocalRef serialize_expiry(JNIEnv *env, const session::config::expiration_mode& mode, const std::chrono::seconds& time_seconds) { - auto none = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$NONE")); - jfieldID none_instance = env->GetStaticFieldID(none.get(), "INSTANCE", "Lnetwork/loki/messenger/libsession_util/util/ExpiryMode$NONE;"); - auto after_send = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$AfterSend")); - jmethodID send_init = env->GetMethodID(after_send.get(), "", "(J)V"); - auto after_read = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$AfterRead")); - jmethodID read_init = env->GetMethodID(after_read.get(), "", "(J)V"); - if (mode == session::config::expiration_mode::none) { + auto none = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$NONE")); + jfieldID none_instance = env->GetStaticFieldID(none.get(), "INSTANCE", "Lnetwork/loki/messenger/libsession_util/util/ExpiryMode$NONE;"); + return {env, env->GetStaticObjectField(none.get(), none_instance)}; } else if (mode == session::config::expiration_mode::after_send) { - return {env, env->NewObject(after_send.get(), send_init, time_seconds.count())}; + static jni_utils::BasicJavaClassInfo class_info( + env, "network/loki/messenger/libsession_util/util/ExpiryMode$AfterSend", + "(J)V" + ); + return {env, env->NewObject(class_info.java_class, class_info.constructor, time_seconds.count())}; } else if (mode == session::config::expiration_mode::after_read) { - return {env, env->NewObject(after_read.get(), read_init, time_seconds.count())}; + static jni_utils::BasicJavaClassInfo class_info( + env, "network/loki/messenger/libsession_util/util/ExpiryMode$AfterRead", + "(J)V" + ); + return {env, env->NewObject(class_info.java_class, class_info.constructor, time_seconds.count())}; } return {env, nullptr}; } @@ -104,9 +111,13 @@ namespace util { if (!optional) { return {env, nullptr}; } - auto longClass = jni_utils::JavaLocalRef(env, env->FindClass("java/lang/Long")); - jmethodID constructor = env->GetMethodID(longClass.get(), "", "(J)V"); - return {env, env->NewObject(longClass.get(), constructor, (jlong)*optional)}; + + static jni_utils::BasicJavaClassInfo class_info( + env, "java/lang/Long", + "(J)V" + ); + + return {env, env->NewObject(class_info.java_class, class_info.constructor, (jlong)*optional)}; } } From 71f46ee10694ecd07ed0f72b09e687b1e02ee82e Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Mon, 24 Nov 2025 16:07:55 +1100 Subject: [PATCH 22/26] Renamed --- library/src/main/cpp/attachments.cpp | 2 +- library/src/main/cpp/blinded_key.cpp | 8 +- library/src/main/cpp/config_base.cpp | 2 +- library/src/main/cpp/contacts.cpp | 12 +-- library/src/main/cpp/contacts.h | 10 --- library/src/main/cpp/conversation.cpp | 117 ++++++++++++++----------- library/src/main/cpp/curve25519.cpp | 2 +- library/src/main/cpp/ed25519.cpp | 6 +- library/src/main/cpp/encryption.cpp | 10 +-- library/src/main/cpp/group_info.cpp | 12 +-- library/src/main/cpp/group_keys.cpp | 20 ++--- library/src/main/cpp/group_members.cpp | 10 +-- library/src/main/cpp/jni_utils.h | 10 +-- library/src/main/cpp/pro_backend.cpp | 6 +- library/src/main/cpp/protocol.cpp | 12 +-- library/src/main/cpp/user_groups.cpp | 20 ++--- library/src/main/cpp/user_profile.cpp | 6 +- library/src/main/cpp/util.cpp | 4 +- libsession-util | 2 +- 19 files changed, 138 insertions(+), 133 deletions(-) delete mode 100644 library/src/main/cpp/contacts.h diff --git a/library/src/main/cpp/attachments.cpp b/library/src/main/cpp/attachments.cpp index 0a7a598..f54be4d 100644 --- a/library/src/main/cpp/attachments.cpp +++ b/library/src/main/cpp/attachments.cpp @@ -50,7 +50,7 @@ Java_network_loki_messenger_libsession_1util_encrypt_Attachments_encryptBytes(JN ); - return util::bytes_from_span(env, std::span(reinterpret_cast(key.data()), key.size())).leak(); + return util::bytes_from_span(env, std::span(reinterpret_cast(key.data()), key.size())).release(); }); } diff --git a/library/src/main/cpp/blinded_key.cpp b/library/src/main/cpp/blinded_key.cpp index 4412663..ddf015a 100644 --- a/library/src/main/cpp/blinded_key.cpp +++ b/library/src/main/cpp/blinded_key.cpp @@ -32,7 +32,7 @@ Java_network_loki_messenger_libsession_1util_util_BlindKeyAPI_blindVersionSign(J session::Platform::android, timestamp ); - return util::bytes_from_vector(env, bytes).leak(); + return util::bytes_from_vector(env, bytes).release(); }); } @@ -53,7 +53,7 @@ Java_network_loki_messenger_libsession_1util_util_BlindKeyAPI_blindVersionSignRe jni_utils::JavaStringRef(env, path).view(), body ? std::make_optional(jni_utils::JavaByteArrayRef(env, body).get()) : std::nullopt ); - return util::bytes_from_vector(env, bytes).leak(); + return util::bytes_from_vector(env, bytes).release(); }); } @@ -84,7 +84,7 @@ Java_network_loki_messenger_libsession_1util_util_BlindKeyAPI_blind15Sign(JNIEnv jni_utils::JavaStringRef(env, server_pub_key).view(), jni_utils::JavaByteArrayRef(env, message).get() ); - return util::bytes_from_vector(env, data).leak(); + return util::bytes_from_vector(env, data).release(); }); } @@ -131,6 +131,6 @@ Java_network_loki_messenger_libsession_1util_util_BlindKeyAPI_blind25Id(JNIEnv * return jni_utils::jstring_from_optional(env, session::blind25_id( jni_utils::JavaStringRef(env, session_id).view(), jni_utils::JavaStringRef(env, server_pub_key).view() - )).leak(); + )).release(); }); } \ No newline at end of file diff --git a/library/src/main/cpp/config_base.cpp b/library/src/main/cpp/config_base.cpp index 44448c2..5c07ec4 100644 --- a/library/src/main/cpp/config_base.cpp +++ b/library/src/main/cpp/config_base.cpp @@ -91,7 +91,7 @@ JNIEXPORT jbyteArray JNICALL Java_network_loki_messenger_libsession_1util_ConfigBase_dump(JNIEnv *env, jobject thiz) { auto config = ptrToConfigBase(env, thiz); auto dumped = config->dump(); - return util::bytes_from_vector(env, dumped).leak(); + return util::bytes_from_vector(env, dumped).release(); } JNIEXPORT jstring JNICALL diff --git a/library/src/main/cpp/contacts.cpp b/library/src/main/cpp/contacts.cpp index 1d5eb46..85220da 100644 --- a/library/src/main/cpp/contacts.cpp +++ b/library/src/main/cpp/contacts.cpp @@ -1,4 +1,6 @@ -#include "contacts.h" +#include +#include + #include "util.h" #include "jni_utils.h" @@ -103,7 +105,7 @@ Java_network_loki_messenger_libsession_1util_Contacts_get(JNIEnv *env, jobject t auto contacts = ptrToContacts(env, thiz); auto contact = contacts->get(JavaStringRef(env, account_id).view()); if (!contact) return nullptr; - return serialize_contact(env, contact.value()).leak(); + return serialize_contact(env, contact.value()).release(); } ); } @@ -115,7 +117,7 @@ Java_network_loki_messenger_libsession_1util_Contacts_getOrConstruct(JNIEnv *env return run_catching_cxx_exception_or_throws(env, [=] { auto contacts = ptrToContacts(env, thiz); auto contact = contacts->get_or_construct(JavaStringRef(env, account_id).view()); - return serialize_contact(env, contact).leak(); + return serialize_contact(env, contact).release(); }); } @@ -206,7 +208,7 @@ Java_network_loki_messenger_libsession_1util_Contacts_getOrConstructBlinded(JNIE JavaStringRef(env, community_server_url).view(), JavaStringRef(env, community_server_pub_key_hex).view(), JavaStringRef(env, blinded_id).view() - )).leak(); + )).release(); } extern "C" @@ -247,7 +249,7 @@ Java_network_loki_messenger_libsession_1util_Contacts_getBlinded(JNIEnv *env, auto result = ptrToContacts(env, thiz)->get_blinded(JavaStringRef(env, blinded_id).view()); if (result) { - return serialize_blinded_contact(env, *result).leak(); + return serialize_blinded_contact(env, *result).release(); } else { return nullptr; } diff --git a/library/src/main/cpp/contacts.h b/library/src/main/cpp/contacts.h deleted file mode 100644 index 4fa53bd..0000000 --- a/library/src/main/cpp/contacts.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef SESSION_ANDROID_CONTACTS_H -#define SESSION_ANDROID_CONTACTS_H - -#include -#include "session/config/contacts.hpp" - - - - -#endif //SESSION_ANDROID_CONTACTS_H diff --git a/library/src/main/cpp/conversation.cpp b/library/src/main/cpp/conversation.cpp index 311e05c..729ead5 100644 --- a/library/src/main/cpp/conversation.cpp +++ b/library/src/main/cpp/conversation.cpp @@ -50,20 +50,19 @@ JavaLocalRef serialize_one_to_one(JNIEnv *env, const session::config::c } session::config::convo::one_to_one deserialize_one_to_one(JNIEnv *env, jobject info) { - struct ClassInfo { - jclass java_class; + struct ClassInfo : public JavaClassInfo { jmethodID id_getter; jmethodID lastRead_getter; jmethodID unread_getter; - ClassInfo(JNIEnv *env, jclass clazz) - :java_class((jclass) env->NewGlobalRef(clazz)), - id_getter(env->GetMethodID(clazz, "getAccountId", "()Ljava/lang/String;")), - lastRead_getter(env->GetMethodID(clazz, "getLastRead", "()J")), - unread_getter(env->GetMethodID(clazz, "getUnread", "()Z")) {} + ClassInfo(JNIEnv *env, jobject obj) + : JavaClassInfo(env, obj), + id_getter(env->GetMethodID(java_class, "getAccountId", "()Ljava/lang/String;")), + lastRead_getter(env->GetMethodID(java_class, "getLastRead", "()J")), + unread_getter(env->GetMethodID(java_class, "getUnread", "()Z")) {} }; - static ClassInfo class_info(env, JavaLocalRef(env, env->GetObjectClass(info)).get()); + static ClassInfo class_info(env, info); session::config::convo::one_to_one r( JavaStringRef( @@ -92,20 +91,19 @@ JavaLocalRef serialize_community(JNIEnv *env, const session::config::co } session::config::convo::community deserialize_community(JNIEnv *env, jobject info) { - struct ClassInfo { - jclass java_class; + struct ClassInfo : public JavaClassInfo { jmethodID base_community_getter; jmethodID last_read_getter; jmethodID unread_getter; - ClassInfo(JNIEnv *env, jclass clazz) - :java_class((jclass) env->NewGlobalRef(clazz)), - base_community_getter(env->GetMethodID(clazz, "getBaseCommunityInfo", "()Lnetwork/loki/messenger/libsession_util/util/BaseCommunityInfo;")), - last_read_getter(env->GetMethodID(clazz, "getLastRead", "()J")), - unread_getter(env->GetMethodID(clazz, "getUnread", "()Z")) {} + ClassInfo(JNIEnv *env, jobject obj) + : JavaClassInfo(env, obj), + base_community_getter(env->GetMethodID(java_class, "getBaseCommunityInfo", "()Lnetwork/loki/messenger/libsession_util/util/BaseCommunityInfo;")), + last_read_getter(env->GetMethodID(java_class, "getLastRead", "()J")), + unread_getter(env->GetMethodID(java_class, "getUnread", "()Z")) {} }; - static ClassInfo class_info(env, JavaLocalRef(env, env->GetObjectClass(info)).get()); + static ClassInfo class_info(env, info); auto base_community = deserialize_base_community( env, @@ -139,20 +137,19 @@ JavaLocalRef serialize_legacy_group(JNIEnv *env, const session::config: } session::config::convo::legacy_group deserialize_legacy_closed_group(JNIEnv *env, jobject info) { - struct ClassInfo { - jclass java_class; + struct ClassInfo : public JavaClassInfo{ jmethodID groupId_getter; jmethodID lastRead_getter; jmethodID unread_getter; - ClassInfo(JNIEnv *env, jclass clazz) - :java_class((jclass) env->NewGlobalRef(clazz)), - groupId_getter(env->GetMethodID(clazz, "getGroupId", "()Ljava/lang/String;")), - lastRead_getter(env->GetMethodID(clazz, "getLastRead", "()J")), - unread_getter(env->GetMethodID(clazz, "getUnread", "()Z")) {} + ClassInfo(JNIEnv *env, jobject obj) + : JavaClassInfo(env, obj), + groupId_getter(env->GetMethodID(java_class, "getGroupId", "()Ljava/lang/String;")), + lastRead_getter(env->GetMethodID(java_class, "getLastRead", "()J")), + unread_getter(env->GetMethodID(java_class, "getUnread", "()Z")) {} }; - static ClassInfo class_info(env, JavaLocalRef(env, env->GetObjectClass(info)).get()); + static ClassInfo class_info(env, info); session::config::convo::legacy_group lg( JavaStringRef(env, JavaLocalRef(env, static_cast(env->CallObjectMethod(info, class_info.groupId_getter))).get()).view() @@ -177,20 +174,19 @@ JavaLocalRef serialize_closed_group(JNIEnv* env, const session::config: } session::config::convo::group deserialize_closed_group(JNIEnv* env, jobject info) { - struct ClassInfo { - jclass java_class; + struct ClassInfo : public JavaClassInfo { jmethodID id_getter; jmethodID last_read_getter; jmethodID unread_getter; - ClassInfo(JNIEnv *env, jclass clazz) - :java_class((jclass) env->NewGlobalRef(clazz)), - id_getter(env->GetMethodID(clazz, "getAccountId", "()Ljava/lang/String;")), - last_read_getter(env->GetMethodID(clazz, "getLastRead", "()J")), - unread_getter(env->GetMethodID(clazz, "getUnread", "()Z")) {} + ClassInfo(JNIEnv *env, jobject obj) + :JavaClassInfo(env, obj), + id_getter(env->GetMethodID(java_class, "getAccountId", "()Ljava/lang/String;")), + last_read_getter(env->GetMethodID(java_class, "getLastRead", "()J")), + unread_getter(env->GetMethodID(java_class, "getUnread", "()Z")) {} }; - static ClassInfo class_info(env, JavaLocalRef(env, env->GetObjectClass(info)).get()); + static ClassInfo class_info(env, info); session::config::convo::group g( JavaStringRef(env, JavaLocalRef(env, (jstring) env->CallObjectMethod(info, class_info.id_getter)).get()).view()); @@ -212,25 +208,25 @@ JavaLocalRef serialize_blinded_one_to_one(JNIEnv *env, const session::c class_info.constructor, JavaLocalRef(env, env->NewStringUTF(blinded_one_to_one.blinded_session_id.data())).get(), (jlong) blinded_one_to_one.last_read, - (jboolean) blinded_one_to_one.unread + (jboolean) blinded_one_to_one.unread, + serialize_pro_proof_info(env, blinded_one_to_one.pro_gen_index_hash, blinded_one_to_one.pro_expiry_unix_ts).get() )}; } session::config::convo::blinded_one_to_one deserialize_blinded_one_to_one(JNIEnv *env, jobject info) { - struct ClassInfo { - jclass java_class; + struct ClassInfo : public JavaClassInfo { jmethodID id_getter; jmethodID last_read_getter; jmethodID unread_getter; - ClassInfo(JNIEnv *env, jclass clazz) - :java_class((jclass) env->NewGlobalRef(clazz)), - id_getter(env->GetMethodID(clazz, "getBlindedAccountId", "()Ljava/lang/String;")), - last_read_getter(env->GetMethodID(clazz, "getLastRead", "()J")), - unread_getter(env->GetMethodID(clazz, "getUnread", "()Z")) {} + ClassInfo(JNIEnv *env, jobject obj) + : JavaClassInfo(env, obj), + id_getter(env->GetMethodID(java_class, "getBlindedAccountId", "()Ljava/lang/String;")), + last_read_getter(env->GetMethodID(java_class, "getLastRead", "()J")), + unread_getter(env->GetMethodID(java_class, "getUnread", "()Z")) {} }; - static ClassInfo class_info(env, JavaLocalRef(env, env->GetObjectClass(info)).get()); + static ClassInfo class_info(env, info); session::config::convo::blinded_one_to_one r( JavaStringRef(env, JavaLocalRef(env, (jstring) env->CallObjectMethod(info, class_info.id_getter)).get()).view()); @@ -322,7 +318,7 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getOneTo auto convos = ptrToConvoInfo(env, thiz); auto internal = convos->get_1to1(JavaStringRef(env, pub_key_hex).view()); if (internal) { - return serialize_one_to_one(env, *internal).leak(); + return serialize_one_to_one(env, *internal).release(); } return nullptr; } @@ -331,7 +327,7 @@ JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getOrConstructOneToOne( JNIEnv *env, jobject thiz, jstring pub_key_hex) { auto convos = ptrToConvoInfo(env, thiz); - return serialize_one_to_one(env, convos->get_or_construct_1to1(JavaStringRef(env, pub_key_hex).view())).leak(); + return serialize_one_to_one(env, convos->get_or_construct_1to1(JavaStringRef(env, pub_key_hex).view())).release(); } extern "C" JNIEXPORT jboolean JNICALL @@ -349,7 +345,7 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getCommu auto convos = ptrToConvoInfo(env, thiz); auto open = convos->get_community(JavaStringRef(env, base_url).view(), JavaStringRef(env, room).view()); if (open) { - return serialize_community(env, *open).leak(); + return serialize_community(env, *open).release(); } return nullptr; } @@ -362,7 +358,7 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getOrCon JavaStringRef(env, base_url).view(), JavaStringRef(env, room).view(), JavaByteArrayRef(env, pub_key).get()); - return serialize_community(env, community).leak(); + return serialize_community(env, community).release(); } extern "C" JNIEXPORT jobject JNICALL @@ -373,7 +369,7 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getOrCon JavaStringRef(env, base_url).view(), JavaStringRef(env, room).view(), JavaStringRef(env, pub_key_hex).view()); - return serialize_community(env, community).leak(); + return serialize_community(env, community).release(); } extern "C" JNIEXPORT jboolean JNICALL @@ -400,7 +396,7 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getLegac auto convos = ptrToConvoInfo(env, thiz); auto lgc = convos->get_legacy_group(JavaStringRef(env, group_id).view()); if (lgc) { - return serialize_legacy_group(env, *lgc).leak(); + return serialize_legacy_group(env, *lgc).release(); } return nullptr; @@ -411,7 +407,7 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getOrCon JNIEnv *env, jobject thiz, jstring group_id) { auto convos = ptrToConvoInfo(env, thiz); auto lgc = convos->get_or_construct_legacy_group(JavaStringRef(env, group_id).view()); - return serialize_legacy_group(env, lgc).leak(); + return serialize_legacy_group(env, lgc).release(); } extern "C" JNIEXPORT jboolean JNICALL @@ -494,7 +490,7 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getClose auto config = ptrToConvoInfo(env, thiz); auto group = config->get_group(JavaStringRef(env, session_id).view()); if (group) { - return serialize_closed_group(env, *group).leak(); + return serialize_closed_group(env, *group).release(); } return nullptr; } @@ -505,7 +501,7 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getOrCon JNIEnv *env, jobject thiz, jstring session_id) { auto config = ptrToConvoInfo(env, thiz); auto group = config->get_or_construct_group(JavaStringRef(env, session_id).view()); - return serialize_closed_group(env, group).leak(); + return serialize_closed_group(env, group).release(); } extern "C" @@ -567,3 +563,24 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_eraseBli return ptrToConvoInfo(env, thiz)->erase_blinded_1to1(JavaStringRef(env, blinded_id).view()); } +extern "C" +JNIEXPORT jobject JNICALL +Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getBlindedOneToOne( + JNIEnv *env, jobject thiz, jstring pub_key_hex) { + auto blinded = ptrToConvoInfo(env, thiz)->get_blinded_1to1(JavaStringRef(env, pub_key_hex).view()); + if (blinded) { + return serialize_blinded_one_to_one(env, *blinded).release(); + } + return nullptr; +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_allBlindedOneToOnes( + JNIEnv *env, jobject thiz) { + auto convo = ptrToConvoInfo(env, thiz); + return jlist_from_iterator(env, + convo->begin_blinded_1to1(), + convo->end(), + serialize_blinded_one_to_one); +} \ No newline at end of file diff --git a/library/src/main/cpp/curve25519.cpp b/library/src/main/cpp/curve25519.cpp index 2ec9848..837ed77 100644 --- a/library/src/main/cpp/curve25519.cpp +++ b/library/src/main/cpp/curve25519.cpp @@ -23,7 +23,7 @@ Java_network_loki_messenger_libsession_1util_Curve25519_pubKeyFromED25519(JNIEnv jbyteArray ed25519_public_key) { return jni_utils::run_catching_cxx_exception_or_throws(env, [=] { auto pk = session::curve25519::to_curve25519_pubkey(jni_utils::JavaByteArrayRef(env, ed25519_public_key).get()); - return util::bytes_from_span(env, pk).leak(); + return util::bytes_from_span(env, pk).release(); }); } diff --git a/library/src/main/cpp/ed25519.cpp b/library/src/main/cpp/ed25519.cpp index 4de53f2..e5bb3b1 100644 --- a/library/src/main/cpp/ed25519.cpp +++ b/library/src/main/cpp/ed25519.cpp @@ -14,7 +14,7 @@ Java_network_loki_messenger_libsession_1util_ED25519_sign(JNIEnv *env, jobject t jni_utils::JavaByteArrayRef(env, ed25519_private_key).get(), jni_utils::JavaByteArrayRef(env, message).get()); - return util::bytes_from_vector(env, sigs).leak(); + return util::bytes_from_vector(env, sigs).release(); }); } @@ -56,7 +56,7 @@ Java_network_loki_messenger_libsession_1util_ED25519_generateProMasterKey(JNIEnv session::ed25519::ed25519_pro_privkey_for_ed25519_seed( jni_utils::JavaByteArrayRef(env, ed25519_seed).get() ) - ).leak(); + ).release(); }); } @@ -69,6 +69,6 @@ Java_network_loki_messenger_libsession_1util_ED25519_positiveEd25519PubKeyFromCu env, session::xed25519::pubkey( jni_utils::JavaByteArrayRef(env, curve25519_pub_key).get()) - ).leak(); + ).release(); }); } \ No newline at end of file diff --git a/library/src/main/cpp/encryption.cpp b/library/src/main/cpp/encryption.cpp index 48cc471..46c922a 100644 --- a/library/src/main/cpp/encryption.cpp +++ b/library/src/main/cpp/encryption.cpp @@ -50,7 +50,7 @@ Java_network_loki_messenger_libsession_1util_SessionEncrypt_encryptForRecipient( JavaByteArrayRef(env, message).get() ); - return jni_utils::session_bytes_from_range(env, data).leak(); + return jni_utils::session_bytes_from_range(env, data).release(); }); } @@ -92,7 +92,7 @@ Java_network_loki_messenger_libsession_1util_SessionEncrypt_encryptForBlindedRec JavaByteArrayRef(env, message).get() ); - return jni_utils::session_bytes_from_range(env, data).leak(); + return jni_utils::session_bytes_from_range(env, data).release(); }); } @@ -108,7 +108,7 @@ Java_network_loki_messenger_libsession_1util_SessionEncrypt_decryptPushNotificat jni_utils::JavaByteArrayRef(env, secret_key).get() ); - return jni_utils::session_bytes_from_range(env, data).leak(); + return jni_utils::session_bytes_from_range(env, data).release(); }); } @@ -126,7 +126,7 @@ Java_network_loki_messenger_libsession_1util_SessionEncrypt_decryptOnsResponse(J nonce ? std::make_optional(jni_utils::JavaByteArrayRef(env, nonce).get()) : std::nullopt ); - return jni_utils::jstring_from_optional(env, data).leak(); + return jni_utils::jstring_from_optional(env, data).release(); }); } @@ -154,7 +154,7 @@ Java_network_loki_messenger_libsession_1util_SessionEncrypt_calculateECHDAgreeme "secret; is the key valid?"}; } - return util::bytes_from_span(env, shared_secret).leak(); + return util::bytes_from_span(env, shared_secret).release(); }); } diff --git a/library/src/main/cpp/group_info.cpp b/library/src/main/cpp/group_info.cpp index 464688e..ba66554 100644 --- a/library/src/main/cpp/group_info.cpp +++ b/library/src/main/cpp/group_info.cpp @@ -46,21 +46,21 @@ extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_GroupInfoConfig_getCreated(JNIEnv *env, jobject thiz) { auto group_info = ptrToInfo(env, thiz); - return util::jlongFromOptional(env, group_info->get_created()).leak(); + return util::jlongFromOptional(env, group_info->get_created()).release(); } extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_GroupInfoConfig_getDeleteAttachmentsBefore(JNIEnv *env, jobject thiz) { auto group_info = ptrToInfo(env, thiz); - return util::jlongFromOptional(env, group_info->get_delete_attach_before()).leak(); + return util::jlongFromOptional(env, group_info->get_delete_attach_before()).release(); } extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_GroupInfoConfig_getDeleteBefore(JNIEnv *env, jobject thiz) { auto group_info = ptrToInfo(env, thiz); - return util::jlongFromOptional(env, group_info->get_delete_before()).leak(); + return util::jlongFromOptional(env, group_info->get_delete_before()).release(); } extern "C" @@ -80,7 +80,7 @@ extern "C" JNIEXPORT jstring JNICALL Java_network_loki_messenger_libsession_1util_GroupInfoConfig_getName(JNIEnv *env, jobject thiz) { auto group_info = ptrToInfo(env, thiz); - return jni_utils::jstring_from_optional(env, group_info->get_name()).leak(); + return jni_utils::jstring_from_optional(env, group_info->get_name()).release(); } extern "C" @@ -88,7 +88,7 @@ JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_GroupInfoConfig_getProfilePic(JNIEnv *env, jobject thiz) { auto group_info = ptrToInfo(env, thiz); - return util::serialize_user_pic(env, group_info->get_profile_pic()).leak(); + return util::serialize_user_pic(env, group_info->get_profile_pic()).release(); } extern "C" @@ -163,7 +163,7 @@ extern "C" JNIEXPORT jstring JNICALL Java_network_loki_messenger_libsession_1util_GroupInfoConfig_id(JNIEnv *env, jobject thiz) { auto group_info = ptrToInfo(env, thiz); - return jni_utils::jstring_from_optional(env, group_info->id).leak(); + return jni_utils::jstring_from_optional(env, group_info->id).release(); } extern "C" diff --git a/library/src/main/cpp/group_keys.cpp b/library/src/main/cpp/group_keys.cpp index bace503..dc255b9 100644 --- a/library/src/main/cpp/group_keys.cpp +++ b/library/src/main/cpp/group_keys.cpp @@ -109,7 +109,7 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_pendingKey(JNIEnv * if (!pending) { return nullptr; } - return util::bytes_from_span(env, *pending).leak(); + return util::bytes_from_span(env, *pending).release(); } extern "C" @@ -121,7 +121,7 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_pendingConfig(JNIEn if (!pending) { return nullptr; } - return util::bytes_from_span(env, *pending).leak(); + return util::bytes_from_span(env, *pending).release(); } extern "C" @@ -132,7 +132,7 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_rekey(JNIEnv *env, auto info = reinterpret_cast(info_ptr); auto members = reinterpret_cast(members_ptr); auto rekey = keys->rekey(*info, *members); - return util::bytes_from_span(env, rekey).leak(); + return util::bytes_from_span(env, rekey).release(); } extern "C" @@ -140,7 +140,7 @@ JNIEXPORT jbyteArray JNICALL Java_network_loki_messenger_libsession_1util_GroupKeysConfig_dump(JNIEnv *env, jobject thiz) { auto keys = ptrToKeys(env, thiz); auto dump = keys->dump(); - return util::bytes_from_vector(env, dump).leak(); + return util::bytes_from_vector(env, dump).release(); } extern "C" @@ -158,7 +158,7 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_encrypt(JNIEnv *env auto ptr = ptrToKeys(env, thiz); auto plaintext_vector = util::vector_from_bytes(env, plaintext); auto enc = ptr->encrypt_message(plaintext_vector); - return util::bytes_from_vector(env, enc).leak(); + return util::bytes_from_vector(env, enc).release(); }); } @@ -190,7 +190,7 @@ extern "C" JNIEXPORT jbyteArray 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()).leak(); + return util::bytes_from_span(env, ptr->group_enc_key()).release(); } extern "C" @@ -209,7 +209,7 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_makeSubAccount(JNIE jboolean can_delete) { auto ptr = ptrToKeys(env, thiz); auto new_subaccount_key = ptr->swarm_make_subaccount(jni_utils::JavaStringRef(env, session_id).view(), can_write, can_delete); - return util::bytes_from_vector(env, new_subaccount_key).leak(); + return util::bytes_from_vector(env, new_subaccount_key).release(); } extern "C" @@ -221,7 +221,7 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_getSubAccountToken( jboolean can_delete) { auto ptr = ptrToKeys(env, thiz); auto token = ptr->swarm_subaccount_token(jni_utils::JavaStringRef(env, session_id).view(), can_write, can_delete); - return util::bytes_from_vector(env, token).leak(); + return util::bytes_from_vector(env, token).release(); } static jni_utils::JavaLocalRef deserialize_swarm_auth(JNIEnv *env, session::config::groups::Keys::swarm_auth auth) { @@ -245,7 +245,7 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_subAccountSign(JNIE auto message_vector = util::vector_from_bytes(env, message); auto signing_value_vector = util::vector_from_bytes(env, signing_value); auto swarm_auth = ptr->swarm_subaccount_sign(message_vector, signing_value_vector, false); - return deserialize_swarm_auth(env, swarm_auth).leak(); + return deserialize_swarm_auth(env, swarm_auth).release(); } extern "C" @@ -259,7 +259,7 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_supplementFor(JNIEn user_session_ids.push_back(jni_utils::JavaStringRef(env, jni_utils::JavaLocalRef(env, (jstring)(env->GetObjectArrayElement(j_user_session_ids, i))).get()).copy()); } auto supplement = ptr->key_supplement(user_session_ids); - return util::bytes_from_vector(env, supplement).leak(); + return util::bytes_from_vector(env, supplement).release(); } extern "C" JNIEXPORT jint JNICALL diff --git a/library/src/main/cpp/group_members.cpp b/library/src/main/cpp/group_members.cpp index d1531af..b8cad46 100644 --- a/library/src/main/cpp/group_members.cpp +++ b/library/src/main/cpp/group_members.cpp @@ -60,7 +60,7 @@ Java_network_loki_messenger_libsession_1util_GroupMembersConfig_get(JNIEnv *env, if (!member) { return nullptr; } - return serialize_group_member(env, *member).leak(); + return serialize_group_member(env, *member).release(); }); } @@ -71,7 +71,7 @@ Java_network_loki_messenger_libsession_1util_GroupMembersConfig_getOrConstruct(J jstring pub_key_hex) { auto config = ptrToMembers(env, thiz); auto member = config->get_or_construct(JavaStringRef(env, pub_key_hex).view()); - return serialize_group_member(env, member).leak(); + return serialize_group_member(env, member).release(); } extern "C" @@ -155,7 +155,7 @@ extern "C" JNIEXPORT jstring JNICALL Java_network_loki_messenger_libsession_1util_util_GroupMember_nameString(JNIEnv *env, jobject thiz) { - return jni_utils::jstring_from_optional(env, ptrToMember(env, thiz)->name).leak(); + return jni_utils::jstring_from_optional(env, ptrToMember(env, thiz)->name).release(); } extern "C" @@ -175,7 +175,7 @@ extern "C" JNIEXPORT jstring JNICALL Java_network_loki_messenger_libsession_1util_util_GroupMember_accountId(JNIEnv *env, jobject thiz) { - return jni_utils::jstring_from_optional(env, ptrToMember(env, thiz)->session_id).leak(); + return jni_utils::jstring_from_optional(env, ptrToMember(env, thiz)->session_id).release(); } extern "C" @@ -188,7 +188,7 @@ extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_util_GroupMember_profilePic(JNIEnv *env, jobject thiz) { - return util::serialize_user_pic(env, ptrToMember(env, thiz)->profile_picture).leak(); + return util::serialize_user_pic(env, ptrToMember(env, thiz)->profile_picture).release(); } extern "C" diff --git a/library/src/main/cpp/jni_utils.h b/library/src/main/cpp/jni_utils.h index 02b8a1e..2248688 100644 --- a/library/src/main/cpp/jni_utils.h +++ b/library/src/main/cpp/jni_utils.h @@ -90,7 +90,8 @@ namespace jni_utils { return ref_; } - JNIType leak() { + // Release the jobject without deleting the local reference + JNIType release() { auto r = ref_; ref_ = nullptr; return r; @@ -115,12 +116,7 @@ namespace jni_utils { BasicJavaClassInfo(JNIEnv *env, const char *class_name, const char *constructor_signature) :JavaClassInfo(env, class_name), - constructor(env->GetMethodID(java_class, "", constructor_signature)) { - if (env->ExceptionCheck()) { - env->ExceptionDescribe(); - throw std::runtime_error("Failed to find constructor for class " + std::string(class_name)); - } - } + constructor(env->GetMethodID(java_class, "", constructor_signature)) {} }; diff --git a/library/src/main/cpp/pro_backend.cpp b/library/src/main/cpp/pro_backend.cpp index 5cc0588..d40a82f 100644 --- a/library/src/main/cpp/pro_backend.cpp +++ b/library/src/main/cpp/pro_backend.cpp @@ -21,7 +21,7 @@ Java_network_loki_messenger_libsession_1util_pro_BackendRequests_buildAddProPaym JavaStringRef(env, payment_id).get_raw(), JavaStringRef(env, order_id).get_raw()); - return jni_utils::jstring_from_optional(env, json).leak(); + return jni_utils::jstring_from_optional(env, json).release(); }); } @@ -40,7 +40,7 @@ Java_network_loki_messenger_libsession_1util_pro_BackendRequests_buildGeneratePr } ); - return jni_utils::jstring_from_optional(env, json).leak(); + return jni_utils::jstring_from_optional(env, json).release(); }); } @@ -59,7 +59,7 @@ Java_network_loki_messenger_libsession_1util_pro_BackendRequests_buildGetProDeta static_cast(count) ); - return jni_utils::jstring_from_optional(env, json).leak(); + return jni_utils::jstring_from_optional(env, json).release(); }); } diff --git a/library/src/main/cpp/protocol.cpp b/library/src/main/cpp/protocol.cpp index 064c0a7..105ae81 100644 --- a/library/src/main/cpp/protocol.cpp +++ b/library/src/main/cpp/protocol.cpp @@ -72,7 +72,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeFor1 rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) : std::nullopt ) - ).leak(); + ).release(); }); } @@ -94,7 +94,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeForC rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) : std::nullopt ) - ).leak(); + ).release(); }); } @@ -125,7 +125,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeForG rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) : std::nullopt ) - ).leak(); + ).release(); }); } @@ -179,7 +179,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeForC rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) : std::nullopt ) - ).leak(); + ).release(); }); } @@ -206,7 +206,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeFor1 std::chrono::sys_time{ std::chrono::milliseconds{now_epoch_ms}}, *java_to_cpp_array<32>(env, pro_backend_pub_key) - )).leak(); + )).release(); }); } @@ -243,7 +243,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeForG std::chrono::sys_time{ std::chrono::milliseconds{now_epoch_ms}}, *java_to_cpp_array<32>(env, pro_backend_pub_key) - )).leak(); + )).release(); }); } diff --git a/library/src/main/cpp/user_groups.cpp b/library/src/main/cpp/user_groups.cpp index 91b9f96..936721b 100644 --- a/library/src/main/cpp/user_groups.cpp +++ b/library/src/main/cpp/user_groups.cpp @@ -133,8 +133,8 @@ static JavaLocalRef serialize_legacy_group_info(JNIEnv *env, session::c static JavaLocalRef serialize_closed_group_info(JNIEnv* env, session::config::group_info info) { auto session_id = jstring_from_optional(env, info.id); - auto admin_bytes = JavaLocalRef(env, info.secretkey.empty() ? nullptr : session_bytes_from_range(env, info.secretkey).leak()); - auto auth_bytes = JavaLocalRef(env, info.auth_data.empty() ? nullptr : session_bytes_from_range(env, info.auth_data).leak()); + auto admin_bytes = JavaLocalRef(env, info.secretkey.empty() ? nullptr : session_bytes_from_range(env, info.secretkey).release()); + auto auth_bytes = JavaLocalRef(env, info.auth_data.empty() ? nullptr : session_bytes_from_range(env, info.auth_data).release()); auto name = jstring_from_optional(env, info.name); static BasicJavaClassInfo class_info( @@ -274,7 +274,7 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_getCommunityInfo(J auto community = conf->get_community(JavaStringRef(env, base_url).view(), JavaStringRef(env, room).view()); if (community) { - return serialize_community_info(env, *community).leak(); + return serialize_community_info(env, *community).release(); } return nullptr; @@ -289,7 +289,7 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_getLegacyGroupInfo auto legacy_group = conf->get_legacy_group(JavaStringRef(env, account_id).view()); jobject return_group = nullptr; if (legacy_group) { - return_group = serialize_legacy_group_info(env, *legacy_group).leak(); + return_group = serialize_legacy_group_info(env, *legacy_group).release(); } return return_group; } @@ -305,7 +305,7 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_getOrConstructComm JavaStringRef(env, room).view(), JavaStringRef(env, pub_key_hex).view()); - return serialize_community_info(env, group).leak(); + return serialize_community_info(env, group).release(); } extern "C" @@ -314,7 +314,7 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_getOrConstructLega JNIEnv *env, jobject thiz, jstring account_id) { auto conf = ptrToUserGroups(env, thiz); auto group = conf->get_or_construct_legacy_group(JavaStringRef(env, account_id).view()); - return serialize_legacy_group_info(env, group).leak(); + return serialize_legacy_group_info(env, group).release(); } extern "C" @@ -466,7 +466,7 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_getClosedGroup(JNI auto group = config->get_group(JavaStringRef(env, session_id).view()); if (group) { - return serialize_closed_group_info(env, *group).leak(); + return serialize_closed_group_info(env, *group).release(); } return nullptr; } @@ -478,7 +478,7 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_getOrConstructClos jstring session_id) { auto config = ptrToUserGroups(env, thiz); auto group = config->get_or_construct_group(JavaStringRef(env, session_id).view()); - return serialize_closed_group_info(env, group).leak(); + return serialize_closed_group_info(env, group).release(); } extern "C" @@ -496,7 +496,7 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_createGroup(JNIEnv auto config = ptrToUserGroups(env, thiz); auto group = config->create_group(); - return serialize_closed_group_info(env, group).leak(); + return serialize_closed_group_info(env, group).release(); } extern "C" @@ -530,5 +530,5 @@ Java_network_loki_messenger_libsession_1util_util_GroupInfo_00024ClosedGroupInfo auto admin_key = session::ed25519::ed25519_key_pair( JavaByteArrayRef(env, seed).get()).second; - return util::bytes_from_span(env, std::span(admin_key.data(), admin_key.size())).leak(); + return util::bytes_from_span(env, std::span(admin_key.data(), admin_key.size())).release(); } \ No newline at end of file diff --git a/library/src/main/cpp/user_profile.cpp b/library/src/main/cpp/user_profile.cpp index ec4443f..c06790f 100644 --- a/library/src/main/cpp/user_profile.cpp +++ b/library/src/main/cpp/user_profile.cpp @@ -30,7 +30,7 @@ JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_UserProfile_getPic(JNIEnv *env, jobject thiz) { auto profile = ptrToProfile(env, thiz); auto pic = profile->get_profile_pic(); - return util::serialize_user_pic(env, pic).leak(); + return util::serialize_user_pic(env, pic).release(); } JNIEXPORT void JNICALL @@ -71,11 +71,11 @@ Java_network_loki_messenger_libsession_1util_UserProfile_getNtsExpiry(JNIEnv *en if (nts_expiry == std::nullopt) { auto expiry = util::serialize_expiry(env, session::config::expiration_mode::none, std::chrono::seconds(0)); - return expiry.leak(); + return expiry.release(); } auto expiry = util::serialize_expiry(env, session::config::expiration_mode::after_send, std::chrono::seconds(*nts_expiry)); - return expiry.leak(); + return expiry.release(); } extern "C" diff --git a/library/src/main/cpp/util.cpp b/library/src/main/cpp/util.cpp index 5bfa8c2..e756950 100644 --- a/library/src/main/cpp/util.cpp +++ b/library/src/main/cpp/util.cpp @@ -161,7 +161,7 @@ Java_network_loki_messenger_libsession_1util_util_MultiEncrypt_encryptForMultipl std::span {random_nonce.data(), 24} ); - return util::bytes_from_vector(env, result).leak(); + return util::bytes_from_vector(env, result).release(); } extern "C" @@ -180,7 +180,7 @@ Java_network_loki_messenger_libsession_1util_util_MultiEncrypt_decryptForMultipl ); if (result) { - return util::bytes_from_vector(env, *result).leak(); + return util::bytes_from_vector(env, *result).release(); } else { LOGD("no result from decrypt"); } diff --git a/libsession-util b/libsession-util index 3731a9f..47acb57 160000 --- a/libsession-util +++ b/libsession-util @@ -1 +1 @@ -Subproject commit 3731a9f90fb6be5e98a970ad8a2956c8fcb2e68c +Subproject commit 47acb57697cd1ec22c3ac4b40252bd2e3fac0a84 From 8f1009c5f60c117ff9f84fe96e35a0ae55fb31c3 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Mon, 24 Nov 2025 16:10:01 +1100 Subject: [PATCH 23/26] Removed unused files --- library/src/main/cpp/group_keys.cpp | 1 - library/src/main/cpp/group_members.cpp | 27 +++++++++++++------------- library/src/main/cpp/group_members.h | 11 ----------- 3 files changed, 13 insertions(+), 26 deletions(-) delete mode 100644 library/src/main/cpp/group_members.h diff --git a/library/src/main/cpp/group_keys.cpp b/library/src/main/cpp/group_keys.cpp index dc255b9..1c2459d 100644 --- a/library/src/main/cpp/group_keys.cpp +++ b/library/src/main/cpp/group_keys.cpp @@ -1,6 +1,5 @@ #include -#include "group_members.h" #include "jni_utils.h" #include "util.h" #include "config_base.h" diff --git a/library/src/main/cpp/group_members.cpp b/library/src/main/cpp/group_members.cpp index b8cad46..d477725 100644 --- a/library/src/main/cpp/group_members.cpp +++ b/library/src/main/cpp/group_members.cpp @@ -1,4 +1,3 @@ -#include "group_members.h" #include "jni_utils.h" #include "util.h" #include "config_base.h" @@ -14,6 +13,19 @@ inline session::config::groups::member *ptrToMember(JNIEnv *env, jobject thiz) { return reinterpret_cast(env->GetLongField(thiz, ptrField)); } +static JavaLocalRef serialize_group_member(JNIEnv* env, const session::config::groups::member& member) { + static BasicJavaClassInfo class_info( + env, + "network/loki/messenger/libsession_util/util/GroupMember", + "(J)V"); + + return {env, env->NewObject( + class_info.java_class, + class_info.constructor, + reinterpret_cast(new session::config::groups::member(member)) + )}; +} + extern "C" JNIEXPORT jlong JNICALL Java_network_loki_messenger_libsession_1util_GroupMembersConfig_00024Companion_newInstance( @@ -222,16 +234,3 @@ Java_network_loki_messenger_libsession_1util_GroupMembersConfig_setPendingSend(J jboolean pending) { ptrToMembers(env, thiz)->set_pending_send(JavaStringRef(env, pub_key_hex).copy(), pending); } - -JavaLocalRef serialize_group_member(JNIEnv* env, const session::config::groups::member& member) { - static BasicJavaClassInfo class_info( - env, - "network/loki/messenger/libsession_util/util/GroupMember", - "(J)V"); - - return {env, env->NewObject( - class_info.java_class, - class_info.constructor, - reinterpret_cast(new session::config::groups::member(member)) - )}; -} \ No newline at end of file diff --git a/library/src/main/cpp/group_members.h b/library/src/main/cpp/group_members.h deleted file mode 100644 index 3ef9a51..0000000 --- a/library/src/main/cpp/group_members.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef SESSION_ANDROID_GROUP_MEMBERS_H -#define SESSION_ANDROID_GROUP_MEMBERS_H - -#include "jni_utils.h" - -#include - - -jni_utils::JavaLocalRef serialize_group_member(JNIEnv* env, const session::config::groups::member& member); - -#endif //SESSION_ANDROID_GROUP_MEMBERS_H From e5105d087ee49b9c952cc3f6e6bbdd5d8e4328a3 Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Mon, 24 Nov 2025 16:11:45 +1100 Subject: [PATCH 24/26] Tidy up --- library/src/main/cpp/pro_proof_util.cpp | 6 +++--- library/src/main/cpp/pro_proof_util.h | 4 +++- library/src/main/cpp/protocol.cpp | 4 ++-- library/src/main/cpp/user_profile.cpp | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/library/src/main/cpp/pro_proof_util.cpp b/library/src/main/cpp/pro_proof_util.cpp index cdced32..48e2fcb 100644 --- a/library/src/main/cpp/pro_proof_util.cpp +++ b/library/src/main/cpp/pro_proof_util.cpp @@ -51,12 +51,12 @@ session::ProProof java_to_cpp_proof(JNIEnv *env, jobject proof) { }; } -jobject cpp_to_java_proof(JNIEnv *env, const session::ProProof &proof) { +JavaLocalRef cpp_to_java_proof(JNIEnv *env, const session::ProProof &proof) { static BasicJavaClassInfo class_info(env, "network/loki/messenger/libsession_util/pro/ProProof", "(I[B[BJ[B)V"); - return env->NewObject( + return {env, env->NewObject( class_info.java_class, class_info.constructor, static_cast(proof.version), @@ -64,7 +64,7 @@ jobject cpp_to_java_proof(JNIEnv *env, const session::ProProof &proof) { util::bytes_from_span(env, proof.rotating_pubkey).get(), static_cast(proof.expiry_unix_ts.time_since_epoch().count()), util::bytes_from_span(env, proof.sig).get() - ); + )}; } extern "C" diff --git a/library/src/main/cpp/pro_proof_util.h b/library/src/main/cpp/pro_proof_util.h index d103fc8..c91d97b 100644 --- a/library/src/main/cpp/pro_proof_util.h +++ b/library/src/main/cpp/pro_proof_util.h @@ -3,5 +3,7 @@ #include #include +#include "jni_utils.h" + session::ProProof java_to_cpp_proof(JNIEnv *, jobject proof); -jobject cpp_to_java_proof(JNIEnv *, const session::ProProof &proof); \ No newline at end of file +jni_utils::JavaLocalRef cpp_to_java_proof(JNIEnv *, const session::ProProof &proof); \ No newline at end of file diff --git a/library/src/main/cpp/protocol.cpp b/library/src/main/cpp/protocol.cpp index 105ae81..dae45d4 100644 --- a/library/src/main/cpp/protocol.cpp +++ b/library/src/main/cpp/protocol.cpp @@ -43,7 +43,7 @@ static JavaLocalRef serializeDecodedEnvelope(JNIEnv *env, const session serializeEnvelop(env, envelop.envelope).get(), envelop.pro ? static_cast(envelop.pro->status) : static_cast(-1), - envelop.pro ? JavaLocalRef(env, cpp_to_java_proof(env, envelop.pro->proof)).get() : nullptr, + envelop.pro ? cpp_to_java_proof(env, envelop.pro->proof).get() : nullptr, static_cast(envelop.pro ? envelop.pro->features : 0), content.get(), sender_ed25519.get(), @@ -157,7 +157,7 @@ Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeForC init, decoded.pro ? static_cast(decoded.pro->status) : static_cast(-1), - decoded.pro ? JavaLocalRef(env, cpp_to_java_proof(env, decoded.pro->proof)).get() : nullptr, + decoded.pro ? cpp_to_java_proof(env, decoded.pro->proof).get() : nullptr, static_cast(decoded.pro ? decoded.pro->features : 0), util::bytes_from_vector(env, decoded.content_plaintext).get() ); diff --git a/library/src/main/cpp/user_profile.cpp b/library/src/main/cpp/user_profile.cpp index c06790f..2e3a5db 100644 --- a/library/src/main/cpp/user_profile.cpp +++ b/library/src/main/cpp/user_profile.cpp @@ -203,7 +203,7 @@ Java_network_loki_messenger_libsession_1util_UserProfile_getProConfig(JNIEnv *en return env->NewObject(class_info.java_class, class_info.constructor, - cpp_to_java_proof(env, profile->proof), + cpp_to_java_proof(env, profile->proof).get(), util::bytes_from_span(env, profile->rotating_privkey).get() ); } From b32447a6881a22deec74b4e9f93827d98e4bf82a Mon Sep 17 00:00:00 2001 From: SessionHero01 Date: Mon, 24 Nov 2025 16:42:15 +1100 Subject: [PATCH 25/26] Pro features in config --- library/src/main/cpp/contacts.cpp | 99 ++++++++++++------- .../libsession_util/util/BlindedContact.kt | 6 ++ .../messenger/libsession_util/util/Contact.kt | 7 ++ 3 files changed, 76 insertions(+), 36 deletions(-) diff --git a/library/src/main/cpp/contacts.cpp b/library/src/main/cpp/contacts.cpp index 85220da..cd3ce95 100644 --- a/library/src/main/cpp/contacts.cpp +++ b/library/src/main/cpp/contacts.cpp @@ -12,10 +12,10 @@ static session::config::Contacts *ptrToContacts(JNIEnv *env, jobject obj) { return (session::config::Contacts *) env->GetLongField(obj, pointerField); } -static JavaLocalRef serialize_contact(JNIEnv *env, session::config::contact_info info) { +static JavaLocalRef serialize_contact(JNIEnv *env, const session::config::contact_info &info) { static BasicJavaClassInfo class_info( env, "network/loki/messenger/libsession_util/util/Contact", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZLnetwork/loki/messenger/libsession_util/util/UserPic;JJJLnetwork/loki/messenger/libsession_util/util/ExpiryMode;)V"); + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZLnetwork/loki/messenger/libsession_util/util/UserPic;JJJLnetwork/loki/messenger/libsession_util/util/ExpiryMode;J)V"); jobject returnObj = env->NewObject(class_info.java_class, class_info.constructor, @@ -29,13 +29,13 @@ static JavaLocalRef serialize_contact(JNIEnv *env, session::config::con (jlong) info.created, (jlong) (info.profile_updated.time_since_epoch().count()), (jlong) info.priority, - util::serialize_expiry(env, info.exp_mode, info.exp_timer).get()); + util::serialize_expiry(env, info.exp_mode, info.exp_timer).get(), + (jlong) info.pro_features); return {env, returnObj}; } session::config::contact_info deserialize_contact(JNIEnv *env, jobject info, session::config::Contacts *conf) { - struct ClassInfo { - jclass java_class; + struct ClassInfo : JavaClassInfo { jmethodID get_id; jmethodID get_name; jmethodID get_nick; @@ -46,19 +46,21 @@ session::config::contact_info deserialize_contact(JNIEnv *env, jobject info, ses jmethodID get_priority; jmethodID get_expiry; jmethodID get_profile_updated; + jmethodID get_pro_features; - ClassInfo(JNIEnv *env, jclass clazz): - java_class((jclass) env->NewGlobalRef(clazz)), - get_id(env->GetMethodID(clazz, "getId", "()Ljava/lang/String;")), - get_name(env->GetMethodID(clazz, "getName", "()Ljava/lang/String;")), - get_nick(env->GetMethodID(clazz, "getNickname", "()Ljava/lang/String;")), - get_approved(env->GetMethodID(clazz, "getApproved", "()Z")), - get_approved_me(env->GetMethodID(clazz, "getApprovedMe", "()Z")), - get_blocked(env->GetMethodID(clazz, "getBlocked", "()Z")), - get_user_pic(env->GetMethodID(clazz, "getProfilePicture", "()Lnetwork/loki/messenger/libsession_util/util/UserPic;")), - get_priority(env->GetMethodID(clazz, "getPriority", "()J")), - get_expiry(env->GetMethodID(clazz, "getExpiryMode", "()Lnetwork/loki/messenger/libsession_util/util/ExpiryMode;")), - get_profile_updated(env->GetMethodID(clazz, "getProfileUpdatedEpochSeconds", "()J")) {} + ClassInfo(JNIEnv *env, jobject obj): + JavaClassInfo(env, obj), + get_id(env->GetMethodID(java_class, "getId", "()Ljava/lang/String;")), + get_name(env->GetMethodID(java_class, "getName", "()Ljava/lang/String;")), + get_nick(env->GetMethodID(java_class, "getNickname", "()Ljava/lang/String;")), + get_approved(env->GetMethodID(java_class, "getApproved", "()Z")), + get_approved_me(env->GetMethodID(java_class, "getApprovedMe", "()Z")), + get_blocked(env->GetMethodID(java_class, "getBlocked", "()Z")), + get_user_pic(env->GetMethodID(java_class, "getProfilePicture", "()Lnetwork/loki/messenger/libsession_util/util/UserPic;")), + get_priority(env->GetMethodID(java_class, "getPriority", "()J")), + get_expiry(env->GetMethodID(java_class, "getExpiryMode", "()Lnetwork/loki/messenger/libsession_util/util/ExpiryMode;")), + get_profile_updated(env->GetMethodID(java_class, "getProfileUpdatedEpochSeconds", "()J")), + get_pro_features(env->GetMethodID(java_class, "getProFeaturesRaw", "()J")) {} }; static ClassInfo class_info(env, JavaLocalRef(env, env->GetObjectClass(info)).get()); @@ -90,6 +92,7 @@ session::config::contact_info deserialize_contact(JNIEnv *env, jobject info, ses contact_info.priority = env->CallLongMethod(info, class_info.get_priority); contact_info.exp_mode = expiry_pair.first; contact_info.exp_timer = std::chrono::seconds(expiry_pair.second); + contact_info.pro_features = env->CallLongMethod(info, class_info.get_pro_features); return contact_info; } @@ -156,7 +159,7 @@ Java_network_loki_messenger_libsession_1util_Contacts_all(JNIEnv *env, jobject t JavaLocalRef serialize_blinded_contact(JNIEnv *env, const session::config::blinded_contact_info &info) { static BasicJavaClassInfo class_info( env, "network/loki/messenger/libsession_util/util/BlindedContact", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JJLnetwork/loki/messenger/libsession_util/util/UserPic;J)V"); + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JJLnetwork/loki/messenger/libsession_util/util/UserPic;JJ)V"); return {env, env->NewObject( class_info.java_class, @@ -168,31 +171,55 @@ JavaLocalRef serialize_blinded_contact(JNIEnv *env, const session::conf (jlong) (info.created.time_since_epoch().count()), (jlong) (info.profile_updated.time_since_epoch().count()), util::serialize_user_pic(env, info.profile_picture).get(), - (jlong) info.priority + (jlong) info.priority, + (jlong) info.pro_features )}; } session::config::blinded_contact_info deserialize_blinded_contact(JNIEnv *env, jobject jInfo) { - JavaLocalRef clazz(env, env->GetObjectClass(jInfo)); - auto idField = env->GetFieldID(clazz.get(), "id", "Ljava/lang/String;"); - auto communityServerField = env->GetFieldID(clazz.get(), "communityServer", "Ljava/lang/String;"); - auto getCommunityServerPubKey = env->GetMethodID(clazz.get(), "getCommunityServerPubKey", "()[B"); - auto nameField = env->GetFieldID(clazz.get(), "name", "Ljava/lang/String;"); - auto createdEpochSecondsField = env->GetFieldID(clazz.get(), "createdEpochSeconds", "J"); - auto profileUpdatedEpochSecondsField = env->GetFieldID(clazz.get(), "profileUpdatedEpochSeconds", "J"); - auto profilePicField = env->GetFieldID(clazz.get(), "profilePic", "Lnetwork/loki/messenger/libsession_util/util/UserPic;"); - auto priorityField = env->GetFieldID(clazz.get(), "priority", "J"); + struct ClassInfo : public JavaClassInfo { + jmethodID id_getter; + jmethodID community_server_getter; + jmethodID community_server_pub_key_getter; + jmethodID name_getter; + jmethodID created_epoch_seconds_getter; + jmethodID profile_updated_epoch_seconds_getter; + jmethodID profile_pic_getter; + jmethodID priority_getter; + jmethodID pro_features_getter; + + ClassInfo(JNIEnv *env, jobject obj) + : JavaClassInfo(env, obj) + , id_getter(env->GetMethodID(java_class, "getId", "()Ljava/lang/String;")) + , community_server_getter(env->GetMethodID(java_class, "getCommunityServer", "()Ljava/lang/String;")) + , community_server_pub_key_getter(env->GetMethodID(java_class, "getCommunityServerPubKey", "()[B")) + , name_getter(env->GetMethodID(java_class, "getName", "()Ljava/lang/String;")) + , created_epoch_seconds_getter(env->GetMethodID(java_class, "getCreatedEpochSeconds", "()J")) + , profile_updated_epoch_seconds_getter(env->GetMethodID(java_class, "getProfileUpdatedEpochSeconds", "()J")) + , profile_pic_getter(env->GetMethodID(java_class, "getProfilePicture", "()Lnetwork/loki/messenger/libsession_util/util/UserPic;")) + , priority_getter(env->GetMethodID(java_class, "getPriority", "()J")) + , pro_features_getter(env->GetMethodID(java_class, "getProFeaturesRaw", "()J")) {} + }; + + static ClassInfo class_info(env, jInfo); + + JavaLocalRef + community_server(env, (jstring) env->CallObjectMethod(jInfo, class_info.community_server_getter)), + id(env, (jstring) env->CallObjectMethod(jInfo, class_info.id_getter)); + + JavaLocalRef community_server_pub_key(env, (jbyteArray) env->CallObjectMethod(jInfo, class_info.community_server_pub_key_getter)); session::config::blinded_contact_info info( - JavaStringRef(env, (jstring) env->GetObjectField(jInfo, communityServerField)).view(), - JavaByteArrayRef(env, (jbyteArray) env->CallObjectMethod(jInfo, getCommunityServerPubKey)).get(), - JavaStringRef(env, (jstring) env->GetObjectField(jInfo, idField)).view() + JavaStringRef(env, community_server.get()).view(), + JavaByteArrayRef(env, community_server_pub_key.get()).get(), + JavaStringRef(env, id.get()).view() ); - info.created = std::chrono::sys_seconds{std::chrono::seconds{env->GetLongField(jInfo, createdEpochSecondsField)}}; - info.profile_picture = util::deserialize_user_pic(env, JavaLocalRef(env, env->GetObjectField(jInfo, profilePicField)).get()); - info.name = JavaStringRef(env, JavaLocalRef(env, (jstring) env->GetObjectField(jInfo, nameField)).get()).view(); - info.profile_updated = std::chrono::sys_seconds{std::chrono::seconds{env->GetLongField(jInfo, profileUpdatedEpochSecondsField)}}; - info.priority = env->GetLongField(jInfo, priorityField); + info.created = std::chrono::sys_seconds{std::chrono::seconds{env->CallLongMethod(jInfo, class_info.created_epoch_seconds_getter)}}; + info.profile_picture = util::deserialize_user_pic(env, JavaLocalRef(env, env->CallObjectMethod(jInfo, class_info.profile_pic_getter)).get()); + info.name = JavaStringRef(env, JavaLocalRef(env, (jstring) env->CallObjectMethod(jInfo, class_info.name_getter)).get()).view(); + info.profile_updated = std::chrono::sys_seconds{std::chrono::seconds{env->CallLongMethod(jInfo, class_info.profile_updated_epoch_seconds_getter)}}; + info.priority = env->CallLongMethod(jInfo, class_info.priority_getter); + info.pro_features = env->CallLongMethod(jInfo, class_info.pro_features_getter); return info; } diff --git a/library/src/main/java/network/loki/messenger/libsession_util/util/BlindedContact.kt b/library/src/main/java/network/loki/messenger/libsession_util/util/BlindedContact.kt index aa619c1..ff9463c 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/util/BlindedContact.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/util/BlindedContact.kt @@ -1,6 +1,8 @@ package network.loki.messenger.libsession_util.util +import androidx.annotation.Keep import network.loki.messenger.libsession_util.ConversationPriority +import network.loki.messenger.libsession_util.protocol.ProFeatures data class BlindedContact( val id: String, @@ -11,8 +13,12 @@ data class BlindedContact( var profileUpdatedEpochSeconds: Long, var profilePic: UserPic, var priority: ConversationPriority, + val proFeatures: ProFeatures, ) { @OptIn(ExperimentalStdlibApi::class) val communityServerPubKey: ByteArray get() = communityServerPubKeyHex.hexToByteArray() + + @get:Keep + private val proFeaturesRaw: Long get() = proFeatures.rawValue } \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/util/Contact.kt b/library/src/main/java/network/loki/messenger/libsession_util/util/Contact.kt index 61f1bf5..79c5602 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/util/Contact.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/util/Contact.kt @@ -1,7 +1,9 @@ package network.loki.messenger.libsession_util.util +import androidx.annotation.Keep import network.loki.messenger.libsession_util.ConversationPriority import network.loki.messenger.libsession_util.PRIORITY_VISIBLE +import network.loki.messenger.libsession_util.protocol.ProFeatures data class Contact( val id: String, @@ -15,7 +17,12 @@ data class Contact( var profileUpdatedEpochSeconds: Long = 0, var priority: ConversationPriority = PRIORITY_VISIBLE, var expiryMode: ExpiryMode = ExpiryMode.NONE, + var proFeatures: ProFeatures = ProFeatures.NONE, ) { + val displayName: String get() = nickname.ifEmpty { name } + + @get:Keep + private val proFeaturesRaw: Long get() = proFeatures.rawValue } \ No newline at end of file From 627763be8c2532c73c8e1cc68c1fdfe01998bb31 Mon Sep 17 00:00:00 2001 From: fanchao Date: Mon, 24 Nov 2025 23:51:04 +1100 Subject: [PATCH 26/26] Fix crashes --- library/src/main/cpp/contacts.cpp | 2 +- library/src/main/cpp/util.cpp | 70 ++++++++++++++++++------------- 2 files changed, 42 insertions(+), 30 deletions(-) diff --git a/library/src/main/cpp/contacts.cpp b/library/src/main/cpp/contacts.cpp index cd3ce95..b596fc8 100644 --- a/library/src/main/cpp/contacts.cpp +++ b/library/src/main/cpp/contacts.cpp @@ -63,7 +63,7 @@ session::config::contact_info deserialize_contact(JNIEnv *env, jobject info, ses get_pro_features(env->GetMethodID(java_class, "getProFeaturesRaw", "()J")) {} }; - static ClassInfo class_info(env, JavaLocalRef(env, env->GetObjectClass(info)).get()); + static ClassInfo class_info(env, info); JavaLocalRef account_id(env, static_cast(env->CallObjectMethod(info, class_info.get_id))); JavaLocalRef name(env, static_cast(env->CallObjectMethod(info, class_info.get_name))); diff --git a/library/src/main/cpp/util.cpp b/library/src/main/cpp/util.cpp index e756950..f44666e 100644 --- a/library/src/main/cpp/util.cpp +++ b/library/src/main/cpp/util.cpp @@ -35,7 +35,7 @@ namespace util { return {}; } - return jni_utils::JavaByteArrayRef(env, byteArray).copy(); + return JavaByteArrayRef(env, byteArray).copy(); } JavaLocalRef bytes_from_span(JNIEnv* env, std::span from_str) { @@ -47,40 +47,52 @@ namespace util { } JavaLocalRef serialize_user_pic(JNIEnv *env, session::config::profile_pic pic) { - static jni_utils::BasicJavaClassInfo class_info( + static BasicJavaClassInfo class_info( env, "network/loki/messenger/libsession_util/util/UserPic", "(Ljava/lang/String;Lnetwork/loki/messenger/libsession_util/util/Bytes;)V" ); return {env, env->NewObject(class_info.java_class, class_info.constructor, - jni_utils::JavaLocalRef(env, env->NewStringUTF(pic.url.data())).get(), - jni_utils::session_bytes_from_range(env, pic.key).get() + JavaLocalRef(env, env->NewStringUTF(pic.url.data())).get(), + session_bytes_from_range(env, pic.key).get() )}; } session::config::profile_pic deserialize_user_pic(JNIEnv *env, jobject user_pic) { - jni_utils::JavaLocalRef clazz(env, env->GetObjectClass(user_pic)); + struct ClassInfo : public JavaClassInfo { + jmethodID url_getter; + jmethodID key_getter; + + ClassInfo(JNIEnv *env, jobject obj) + : JavaClassInfo(env, obj) + , url_getter(env->GetMethodID(java_class, "getUrl", "()Ljava/lang/String;")) + , key_getter(env->GetMethodID(java_class, "getKeyAsByteArray", "()[B")) + {} + }; + + static ClassInfo class_info(env, user_pic); + return { - jni_utils::JavaStringRef(env, (jstring) (env->CallObjectMethod(user_pic, env->GetMethodID(clazz.get(), "getUrl", "()Ljava/lang/String;")))).view(), - util::vector_from_bytes(env, static_cast(env->CallObjectMethod(user_pic, env->GetMethodID(clazz.get(), "getKeyAsByteArray", "()[B")))) + JavaStringRef(env, (jstring) (env->CallObjectMethod(user_pic, class_info.url_getter))).view(), + util::vector_from_bytes(env, static_cast(env->CallObjectMethod(user_pic, class_info.key_getter))) }; } JavaLocalRef serialize_expiry(JNIEnv *env, const session::config::expiration_mode& mode, const std::chrono::seconds& time_seconds) { if (mode == session::config::expiration_mode::none) { - auto none = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$NONE")); + auto none = JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$NONE")); jfieldID none_instance = env->GetStaticFieldID(none.get(), "INSTANCE", "Lnetwork/loki/messenger/libsession_util/util/ExpiryMode$NONE;"); return {env, env->GetStaticObjectField(none.get(), none_instance)}; } else if (mode == session::config::expiration_mode::after_send) { - static jni_utils::BasicJavaClassInfo class_info( + static BasicJavaClassInfo class_info( env, "network/loki/messenger/libsession_util/util/ExpiryMode$AfterSend", "(J)V" ); return {env, env->NewObject(class_info.java_class, class_info.constructor, time_seconds.count())}; } else if (mode == session::config::expiration_mode::after_read) { - static jni_utils::BasicJavaClassInfo class_info( + static BasicJavaClassInfo class_info( env, "network/loki/messenger/libsession_util/util/ExpiryMode$AfterRead", "(J)V" ); @@ -90,12 +102,12 @@ namespace util { } std::pair deserialize_expiry(JNIEnv *env, jobject expiry_mode) { - auto parent = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode")); - auto after_read = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$AfterRead")); - auto after_send = jni_utils::JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$AfterSend")); + auto parent = JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode")); + auto after_read = JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$AfterRead")); + auto after_send = JavaLocalRef(env, env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$AfterSend")); jfieldID duration_seconds = env->GetFieldID(parent.get(), "expirySeconds", "J"); - auto object_class = jni_utils::JavaLocalRef(env, env->GetObjectClass(expiry_mode)); + auto object_class = JavaLocalRef(env, env->GetObjectClass(expiry_mode)); if (env->IsSameObject(object_class.get(), after_read.get())) { return std::pair(session::config::expiration_mode::after_read, env->GetLongField(expiry_mode, duration_seconds)); @@ -112,7 +124,7 @@ namespace util { return {env, nullptr}; } - static jni_utils::BasicJavaClassInfo class_info( + static BasicJavaClassInfo class_info( env, "java/lang/Long", "(J)V" ); @@ -136,11 +148,11 @@ Java_network_loki_messenger_libsession_1util_util_MultiEncrypt_encryptForMultipl std::vector> message_vec{}; std::vector> recipient_vec{}; for (int i = 0; i < size; i++) { - jni_utils::JavaLocalRef message_j(env, static_cast(env->GetObjectArrayElement(messages, i))); - jni_utils::JavaLocalRef recipient_j(env, static_cast(env->GetObjectArrayElement(recipients, i))); + JavaLocalRef message_j(env, static_cast(env->GetObjectArrayElement(messages, i))); + JavaLocalRef recipient_j(env, static_cast(env->GetObjectArrayElement(recipients, i))); - message_vec.emplace_back(jni_utils::JavaByteArrayRef(env, message_j.get()).copy()); - recipient_vec.emplace_back(jni_utils::JavaByteArrayRef(env, recipient_j.get()).copy()); + message_vec.emplace_back(JavaByteArrayRef(env, message_j.get()).copy()); + recipient_vec.emplace_back(JavaByteArrayRef(env, recipient_j.get()).copy()); } std::vector> message_sv_vec{}; @@ -156,8 +168,8 @@ Java_network_loki_messenger_libsession_1util_util_MultiEncrypt_encryptForMultipl auto result = session::encrypt_for_multiple_simple( message_sv_vec, recipient_sv_vec, - jni_utils::JavaByteArrayRef(env, ed25519_secret_key).get(), - jni_utils::JavaStringRef(env, domain).view(), + JavaByteArrayRef(env, ed25519_secret_key).get(), + JavaStringRef(env, domain).view(), std::span {random_nonce.data(), 24} ); @@ -173,10 +185,10 @@ Java_network_loki_messenger_libsession_1util_util_MultiEncrypt_decryptForMultipl jbyteArray sender_pub_key, jstring domain) { auto result = session::decrypt_for_multiple_simple( - jni_utils::JavaByteArrayRef(env, encoded).get(), - jni_utils::JavaByteArrayRef(env, secret_key).get(), - jni_utils::JavaByteArrayRef(env, sender_pub_key).get(), - jni_utils::JavaStringRef(env, domain).view() + JavaByteArrayRef(env, encoded).get(), + JavaByteArrayRef(env, secret_key).get(), + JavaByteArrayRef(env, sender_pub_key).get(), + JavaStringRef(env, domain).view() ); if (result) { @@ -191,7 +203,7 @@ extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_util_BaseCommunityInfo_00024Companion_parseFullUrl( JNIEnv *env, jobject thiz, jstring full_url) { - auto [base, room, pk] = session::config::community::parse_full_url(jni_utils::JavaStringRef(env, full_url).view()); + auto [base, room, pk] = session::config::community::parse_full_url(JavaStringRef(env, full_url).view()); jclass clazz = env->FindClass("kotlin/Triple"); jmethodID constructor = env->GetMethodID(clazz, "", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V"); @@ -296,8 +308,8 @@ Java_network_loki_messenger_libsession_1util_util_Util_lengthForCodepoints(JNIEn jobject thiz, jstring str, jint max_codepoints) { - return jni_utils::run_catching_cxx_exception_or_throws(env, [=]() { - jni_utils::JavaCharsRef str_ref(env, str); + return run_catching_cxx_exception_or_throws(env, [=]() { + JavaCharsRef str_ref(env, str); return session::utf16_count_truncated_to_codepoints( {reinterpret_cast(str_ref.chars()), str_ref.size()}, max_codepoints @@ -309,6 +321,6 @@ extern "C" JNIEXPORT jint JNICALL Java_network_loki_messenger_libsession_1util_util_Util_countCodepoints(JNIEnv *env, jobject thiz, jstring str) { - jni_utils::JavaCharsRef str_ref(env, str); + JavaCharsRef str_ref(env, str); return session::utf16_count({reinterpret_cast(str_ref.chars()), str_ref.size()}); } \ No newline at end of file