diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 9ff400b..292fb48 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -6,23 +6,49 @@ on: - opened - synchronize +# Limit to one concurrent run per PR +concurrency: + group: "check-pr-${{ github.event.pull_request.number }}" + cancel-in-progress: true + jobs: build: runs-on: ubuntu-latest permissions: contents: read packages: write + pull-requests: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: - submodules: 'recursive' + submodules: "recursive" - name: Set up JDK 17 uses: actions/setup-java@v4 with: - java-version: '17' - distribution: 'temurin' + java-version: "17" + distribution: "temurin" cache: gradle - name: Verify build for PR run: ./gradlew check + + post_version: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + with: + fetch-tags: true + fetch-depth: 0 + + - name: Extract version + id: extract_version + run: | + VERSION=$(git describe --tags --dirty) + echo "version=$VERSION" >> $GITHUB_OUTPUT + - name: Posting comment about the build + uses: marocchino/sticky-pull-request-comment@v2 + with: + header: version + message: | + The build version for this PR will be: `${{ steps.extract_version.outputs.version }}` diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 27ba1cf..69add3c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,6 +7,7 @@ junit = { module = "junit:junit", version = "4.13.2" } androidx-test-runner = { module = "androidx.test:runner", version = "1.7.0" } androidx-test-rules = { module = "androidx.test:rules", version = "1.7.0" } androidx-test-ext = { module = "androidx.test.ext:junit", version = "1.3.0" } +androidx-annotations = { module = "androidx.annotation:annotation", version = "1.9.1" } [plugins] android-library = { id = "com.android.library", version.ref = "agp" } diff --git a/library/build.gradle.kts b/library/build.gradle.kts index da8f693..87a9668 100644 --- a/library/build.gradle.kts +++ b/library/build.gradle.kts @@ -14,7 +14,7 @@ android { compileSdk = 35 defaultConfig { - minSdk = 24 + minSdk = 26 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" @@ -117,4 +117,6 @@ dependencies { androidTestImplementation(libs.androidx.test.runner) androidTestImplementation(libs.androidx.test.rules) androidTestImplementation(libs.androidx.test.ext) + + implementation(libs.androidx.annotations) } diff --git a/library/src/main/cpp/CMakeLists.txt b/library/src/main/cpp/CMakeLists.txt index c91afef..f475972 100644 --- a/library/src/main/cpp/CMakeLists.txt +++ b/library/src/main/cpp/CMakeLists.txt @@ -91,6 +91,7 @@ set(SOURCES ed25519.cpp curve25519.cpp hash.cpp + protocol.cpp attachments.cpp webp_utils.cpp gif_utils.cpp diff --git a/library/src/main/cpp/group_keys.cpp b/library/src/main/cpp/group_keys.cpp index 45f87f7..55f43bc 100644 --- a/library/src/main/cpp/group_keys.cpp +++ b/library/src/main/cpp/group_keys.cpp @@ -187,6 +187,13 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_keys(JNIEnv *env, j return jni_utils::jlist_from_collection(env, ptr->group_keys(), util::bytes_from_span); } +extern "C" +JNIEXPORT jobject JNICALL +Java_network_loki_messenger_libsession_1util_GroupKeysConfig_groupEncKey(JNIEnv *env, jobject thiz) { + auto ptr = ptrToKeys(env, thiz); + return util::bytes_from_span(env, ptr->group_enc_key()); +} + extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_GroupKeysConfig_activeHashes(JNIEnv *env, diff --git a/library/src/main/cpp/jni_utils.h b/library/src/main/cpp/jni_utils.h index 44d599e..c74b6b4 100644 --- a/library/src/main/cpp/jni_utils.h +++ b/library/src/main/cpp/jni_utils.h @@ -69,6 +69,11 @@ namespace jni_utils { env_->DeleteLocalRef(ref_); } } + JavaLocalRef(JavaLocalRef&& other) : env_(other.env_), ref_(other.ref_) { + other.ref_ = nullptr; + } + + JavaLocalRef(const JavaLocalRef&) = delete; void reset(JNIType new_ref) { if (ref_ != new_ref) { @@ -82,6 +87,7 @@ namespace jni_utils { } }; + /** * Create a Java List from an iterator. * @@ -169,6 +175,8 @@ namespace jni_utils { data = std::span(const_cast(c_str), env->GetStringUTFLength(s)); } + JavaStringRef(const JavaStringRef &) = delete; + ~JavaStringRef() { env->ReleaseStringUTFChars(s, data.data()); } @@ -202,8 +210,18 @@ namespace jni_utils { data = std::span(reinterpret_cast(env->GetByteArrayElements(byte_array, nullptr)), length); } + JavaByteArrayRef(const JavaByteArrayRef &) = delete; + + JavaByteArrayRef(JavaByteArrayRef&& other) : env(other.env), byte_array(other.byte_array), data(other.data) { + other.byte_array = nullptr; + other.data = {}; + } + ~JavaByteArrayRef() { - env->ReleaseByteArrayElements(byte_array, reinterpret_cast(data.data()), 0); + if (byte_array) { + env->ReleaseByteArrayElements(byte_array, + reinterpret_cast(data.data()), 0); + } } jbyteArray java_array() const { @@ -235,6 +253,24 @@ namespace jni_utils { return std::vector(data.begin(), data.end()); } }; + + template + static std::optional> java_to_cpp_array(JNIEnv *env, jbyteArray array) { + if (!array) { + return std::nullopt; + } + + JavaByteArrayRef bytes(env, array); + auto span = bytes.get(); + if (span.size() != N) { + throw std::runtime_error("Invalid byte array length from java, expecting " + std::to_string(N) + " got " + std::to_string(span.size())); + } + + std::array out; + std::copy(span.begin(), span.end(), out.begin()); + return out; + } + } #endif //SESSION_ANDROID_JNI_UTILS_H diff --git a/library/src/main/cpp/protocol.cpp b/library/src/main/cpp/protocol.cpp new file mode 100644 index 0000000..653e54a --- /dev/null +++ b/library/src/main/cpp/protocol.cpp @@ -0,0 +1,258 @@ +#include +#include +#include + +#include "jni_utils.h" + +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 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(), + "", + "(J[BJ[B)V" + ); + + return {env, env->NewObject(envelopClass.get(), + init, + static_cast(envelope.timestamp.count()), + (envelope.flags & SESSION_PROTOCOL_ENVELOPE_FLAGS_SOURCE) + ? util::bytes_from_span(env, envelope.source) + : nullptr, + (envelope.flags & SESSION_PROTOCOL_ENVELOPE_FLAGS_SERVER_TIMESTAMP) + ? static_cast(envelope.server_timestamp) + : 0, + util::bytes_from_span(env, envelope.pro_sig))}; +} + +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(), + "", + "(Lnetwork/loki/messenger/libsession_util/protocol/Envelope;Lnetwork/loki/messenger/libsession_util/protocol/ProStatus;[B[B[BJ)V" + ); + + return env->NewObject(envelopClass.get(), init, + serializeEnvelop(env, envelop.envelope).get(), + serializeProStatus(env, envelop.pro).get(), + content.get(), + sender_ed25519.get(), + sender_x25519.get(), + static_cast(envelop.envelope.timestamp.count())); + +} + +extern "C" +JNIEXPORT jbyteArray JNICALL +Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeFor1o1(JNIEnv *env, + jobject thiz, + jbyteArray plaintext, + jbyteArray my_ed25519_priv_key, + jlong timestamp_ms, + jbyteArray recipient_pub_key, + jbyteArray rotating_key) { + return run_catching_cxx_exception_or_throws(env, [=] { + return util::bytes_from_vector( + env, + session::encode_for_1o1( + JavaByteArrayRef(env, plaintext).get(), + JavaByteArrayRef(env, my_ed25519_priv_key).get(), + std::chrono::milliseconds { timestamp_ms }, + *java_to_cpp_array<33>(env, recipient_pub_key), + rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) : std::nullopt + ) + ); + }); +} + +extern "C" +JNIEXPORT jbyteArray JNICALL +Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeForCommunityInbox( + JNIEnv *env, jobject thiz, jbyteArray plaintext, jbyteArray my_ed25519_priv_key, + jlong timestamp_ms, jbyteArray recipient_pub_key, jbyteArray community_server_pub_key, + jbyteArray rotating_key) { + return run_catching_cxx_exception_or_throws(env, [=] { + return util::bytes_from_vector( + env, + session::encode_for_community_inbox( + JavaByteArrayRef(env, plaintext).get(), + JavaByteArrayRef(env, my_ed25519_priv_key).get(), + std::chrono::milliseconds { timestamp_ms }, + *java_to_cpp_array<33>(env, recipient_pub_key), + *java_to_cpp_array<32>(env, community_server_pub_key), + rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) : std::nullopt + ) + ); + }); +} + +extern "C" +JNIEXPORT jbyteArray JNICALL +Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeForGroup(JNIEnv *env, + jobject thiz, + jbyteArray plaintext, + jbyteArray my_ed25519_priv_key, + jlong timestamp_ms, + jbyteArray group_ed25519_public_key, + jbyteArray group_ed25519_private_key, + jbyteArray rotating_key) { + return run_catching_cxx_exception_or_throws(env, [=] { + session::cleared_uc32 group_private_key; + + auto array = *java_to_cpp_array<32>(env, group_ed25519_private_key); + std::copy(array.begin(), array.end(), group_private_key.begin()); + + return util::bytes_from_vector( + env, + session::encode_for_group( + JavaByteArrayRef(env, plaintext).get(), + JavaByteArrayRef(env, my_ed25519_priv_key).get(), + std::chrono::milliseconds { timestamp_ms }, + *java_to_cpp_array<33>(env, group_ed25519_public_key), + group_private_key, + rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) : std::nullopt + ) + ); + }); +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeForCommunity( + JNIEnv *env, jobject thiz, jbyteArray payload, jlong now_epoch_ms, + jbyteArray pro_backend_pub_key) { + return run_catching_cxx_exception_or_throws(env, [=] { + jni_utils::JavaByteArrayRef payload_ref(env, payload); + + auto decoded = session::decode_for_community( + payload_ref.get(), + std::chrono::sys_time { std::chrono::milliseconds { now_epoch_ms } }, + *java_to_cpp_array<32>(env, pro_backend_pub_key) + ); + + JavaLocalRef envelopClass(env, env->FindClass("network/loki/messenger/libsession_util/protocol/DecodedCommunityMessage")); + jmethodID init = env->GetMethodID( + envelopClass.get(), + "", + "(Lnetwork/loki/messenger/libsession_util/protocol/ProStatus;[B)V" + ); + + return env->NewObject( + envelopClass.get(), + init, + serializeProStatus(env, decoded.pro).get(), + util::bytes_from_vector(env, decoded.content_plaintext) + ); + }); +} + +extern "C" +JNIEXPORT jbyteArray JNICALL +Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_encodeForCommunity( + JNIEnv *env, + jobject thiz, + jbyteArray plaintext, + jbyteArray rotating_key) { + return run_catching_cxx_exception_or_throws(env, [=] { + return util::bytes_from_vector( + env, + session::encode_for_community( + JavaByteArrayRef(env, plaintext).get(), + rotating_key ? std::optional(JavaByteArrayRef(env, rotating_key).get()) : std::nullopt + ) + ); + }); +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeFor1o1(JNIEnv *env, + jobject thiz, + jbyteArray key, + jbyteArray payload, + jlong now_epoch_ms, + jbyteArray pro_backend_pub_key) { + return run_catching_cxx_exception_or_throws(env, [=] { + JavaByteArrayRef key_ref(env, key); + + std::array, 1> keys = { key_ref.get() }; + + session::DecodeEnvelopeKey decode_key { + .decrypt_keys = std::span(keys.data(), keys.size()), + }; + + return serializeDecodedEnvelope(env, session::decode_envelope( + decode_key, + JavaByteArrayRef(env, payload).get(), + std::chrono::sys_time { std::chrono::milliseconds { now_epoch_ms } }, + *java_to_cpp_array<32>(env, pro_backend_pub_key) + )); + }); +} + + +extern "C" +JNIEXPORT jobject JNICALL +Java_network_loki_messenger_libsession_1util_protocol_SessionProtocol_decodeForGroup(JNIEnv *env, + jobject thiz, + jbyteArray payload, + jbyteArray my_ed25519_priv_key, + jlong now_epoch_ms, + jbyteArray group_ed25519_public_key, + jobjectArray group_ed25519_private_keys, + jbyteArray pro_backend_pub_key) { + return run_catching_cxx_exception_or_throws(env, [=] { + std::vector private_keys_refs; + std::vector> private_keys_spans; + for (int i = 0, size = env->GetArrayLength(group_ed25519_private_keys); i < size; i++) { + auto bytes = reinterpret_cast(env->GetObjectArrayElement(group_ed25519_private_keys, i)); + private_keys_spans.emplace_back(private_keys_refs.emplace_back(env, bytes).get()); + } + + JavaByteArrayRef group_pub_key_ref(env, group_ed25519_public_key); + + session::DecodeEnvelopeKey decode_key { + .group_ed25519_pubkey = std::make_optional(group_pub_key_ref.get()), + .decrypt_keys = std::span(private_keys_spans.data(), private_keys_spans.size()), + }; + + return serializeDecodedEnvelope(env, session::decode_envelope( + decode_key, + JavaByteArrayRef(env, payload).get(), + std::chrono::sys_time { std::chrono::milliseconds { now_epoch_ms } }, + *java_to_cpp_array<32>(env, pro_backend_pub_key) + )); + }); +} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/Config.kt b/library/src/main/java/network/loki/messenger/libsession_util/Config.kt index c87ed76..3c8d058 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 @@ -231,6 +231,7 @@ sealed class ConfigSig(pointer: Long) : Config(pointer) interface ReadableGroupKeysConfig { fun groupKeys(): List + fun groupEncKey(): ByteArray fun needsDump(): Boolean fun dump(): ByteArray fun needsRekey(): Boolean diff --git a/library/src/main/java/network/loki/messenger/libsession_util/GroupKeysConfig.kt b/library/src/main/java/network/loki/messenger/libsession_util/GroupKeysConfig.kt index 4f7fff9..2970257 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/GroupKeysConfig.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/GroupKeysConfig.kt @@ -39,6 +39,7 @@ class GroupKeysConfig private constructor( override fun namespace() = Namespace.GROUP_KEYS() external override fun groupKeys(): List + external override fun groupEncKey(): ByteArray external override fun needsDump(): Boolean external override fun dump(): ByteArray external fun loadKey(message: ByteArray, diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedCommunityMessage.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedCommunityMessage.kt new file mode 100644 index 0000000..7f8c703 --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedCommunityMessage.kt @@ -0,0 +1,18 @@ +package network.loki.messenger.libsession_util.protocol + +import androidx.annotation.Keep +import network.loki.messenger.libsession_util.util.Bytes + +data class DecodedCommunityMessage( + val proStatus: ProStatus, + val contentPlainText: Bytes, +) { + @Keep + constructor( + proStatus: ProStatus, + contentPlainText: ByteArray, + ): this( + proStatus = proStatus, + contentPlainText = Bytes(contentPlainText), + ) +} diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelope.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelope.kt new file mode 100644 index 0000000..35e1f4d --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/DecodedEnvelope.kt @@ -0,0 +1,31 @@ +package network.loki.messenger.libsession_util.protocol + +import androidx.annotation.Keep +import network.loki.messenger.libsession_util.util.Bytes +import java.time.Instant + +data class DecodedEnvelope( + val envelope: Envelope, + val proStatus: ProStatus, + val contentPlainText: Bytes, + val senderEd25519PubKey: Bytes, + val senderX25519PubKey: Bytes, + val timestamp: Instant +) { + @Keep + constructor( + envelope: Envelope, + proStatus: ProStatus, + contentPlainText: ByteArray, + senderEd25519PubKey: ByteArray, + senderX25519PubKey: ByteArray, + timestampEpochMills: Long + ): this( + envelope = envelope, + proStatus = proStatus, + contentPlainText = Bytes(contentPlainText), + senderEd25519PubKey = Bytes(senderEd25519PubKey), + senderX25519PubKey = Bytes(senderX25519PubKey), + timestamp = Instant.ofEpochMilli(timestampEpochMills) + ) +} diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/Envelope.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/Envelope.kt new file mode 100644 index 0000000..2711d51 --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/Envelope.kt @@ -0,0 +1,25 @@ +package network.loki.messenger.libsession_util.protocol + +import androidx.annotation.Keep +import network.loki.messenger.libsession_util.util.Bytes +import java.time.Instant + +data class Envelope( + val timestamp: Instant, + val source: Bytes?, // 33 bytes prefixed public key + val serverTimestamp: Instant?, + val proSignature: Bytes, // 64 bytes +) { + @Keep + constructor( + timestampMs: Long, + source: ByteArray?, + serverTimestampMs: Long, + proSignature: ByteArray + ): this( + timestamp = Instant.ofEpochMilli(timestampMs), + source = source?.let { Bytes(it) }, + serverTimestamp = if (serverTimestampMs != 0L) Instant.ofEpochMilli(serverTimestampMs) else null, + proSignature = Bytes(proSignature) + ) +} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProFeatures.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProFeatures.kt new file mode 100644 index 0000000..843be42 --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProFeatures.kt @@ -0,0 +1,24 @@ +package network.loki.messenger.libsession_util.protocol + + +enum class ProFeature(internal val bitIndex: Int) { + HIGHER_CHARACTER_LIMIT(0), + PRO_BADGE(1), + ANIMATED_AVATAR(2), +} + +internal fun Long.toFeatures(): Set { + return buildSet(ProFeature.entries.size) { + for (entry in ProFeature.entries) { + if (this@toFeatures and (1L shl entry.bitIndex) != 0L) { + add(entry) + } + } + } +} + +internal fun Collection.toLong(): Long { + return fold(0L) { acc, entry -> + acc or (1L shl entry.bitIndex) + } +} \ No newline at end of file diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProStatus.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProStatus.kt new file mode 100644 index 0000000..49b6a94 --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/ProStatus.kt @@ -0,0 +1,24 @@ +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 diff --git a/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt b/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt new file mode 100644 index 0000000..3d18b85 --- /dev/null +++ b/library/src/main/java/network/loki/messenger/libsession_util/protocol/SessionProtocol.kt @@ -0,0 +1,58 @@ +package network.loki.messenger.libsession_util.protocol + +import network.loki.messenger.libsession_util.LibSessionUtilCApi + +object SessionProtocol : LibSessionUtilCApi() { + external fun encodeFor1o1( + plaintext: ByteArray, + myEd25519PrivKey: ByteArray, + timestampMs: Long, + recipientPubKey: ByteArray, // 33 bytes prefixed key + proRotatingEd25519PrivKey: ByteArray?, // 64 bytes + ): ByteArray + + external fun decodeFor1o1( + myEd25519PrivKey: ByteArray, + payload: ByteArray, + nowEpochMs: Long, + proBackendPubKey: ByteArray, // 32 bytes backend key + ): DecodedEnvelope + + external fun encodeForCommunityInbox( + plaintext: ByteArray, + myEd25519PrivKey: ByteArray, + timestampMs: Long, + recipientPubKey: ByteArray, // 33 bytes prefixed key + communityServerPubKey: ByteArray, // 32 bytes key + proRotatingEd25519PrivKey: ByteArray?, // 64 bytes + ): ByteArray + + external fun encodeForCommunity( + plaintext: ByteArray, + proRotatingEd25519PrivKey: ByteArray?, // 64 bytes + ): ByteArray + + external fun decodeForCommunity( + payload: ByteArray, + nowEpochMs: Long, + proBackendPubKey: ByteArray, // 32 bytes backend key + ): DecodedCommunityMessage + + external fun encodeForGroup( + plaintext: ByteArray, + myEd25519PrivKey: ByteArray, + timestampMs: Long, + groupEd25519PublicKey: ByteArray, // 33 bytes 03 prefixed key + groupEd25519PrivateKey: ByteArray, // 32 bytes group "encryption" key + proRotatingEd25519PrivKey: ByteArray?, // 64 bytes + ): ByteArray + + external fun decodeForGroup( + payload: ByteArray, + myEd25519PrivKey: ByteArray, + nowEpochMs: Long, + groupEd25519PublicKey: ByteArray, // 33 bytes 03 prefixed key + groupEd25519PrivateKeys: Array, // all available group private keys + proBackendPubKey: ByteArray, // 32 bytes backend key + ): DecodedEnvelope +} \ No newline at end of file diff --git a/libsession-util b/libsession-util index 1fdd145..6134c47 160000 --- a/libsession-util +++ b/libsession-util @@ -1 +1 @@ -Subproject commit 1fdd145076cb932a78fdde6e37753bacc2848fff +Subproject commit 6134c4718ae094be53deeb2b4285bed475b20b88