diff --git a/CHANGELOG.md b/CHANGELOG.md index 3736d2c3b9..a16fc52d04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ ### Features +- expose enitre read-only API in Kotlin on the `CoreCrypto` type. This allows reading data without opening a + transaction. + - replaced `CoreCrypto.init(database: Database)` with class constructor `new CoreCrypto(database: Database)` Affected platforms: web diff --git a/crypto-ffi/bindings/jvm/src/main/kotlin/com/wire/crypto/CoreCrypto.kt b/crypto-ffi/bindings/jvm/src/main/kotlin/com/wire/crypto/CoreCrypto.kt index eb55545ac8..28f4aed597 100644 --- a/crypto-ffi/bindings/jvm/src/main/kotlin/com/wire/crypto/CoreCrypto.kt +++ b/crypto-ffi/bindings/jvm/src/main/kotlin/com/wire/crypto/CoreCrypto.kt @@ -17,7 +17,7 @@ fun CoreCryptoFfi.lift() = CoreCrypto(this) * This wrapper should be largely transparent to end users. It exists to improve the * callback interfaces: `.transaction(...)`, `.registerFooObserver(...)`, etc. */ -class CoreCrypto(private val cc: CoreCryptoFfi) { +class CoreCrypto(private val cc: CoreCryptoFfi) : CoreCryptoFfiInterface by cc { companion object { /** Opens a core crypto client with the specified database, previously instantiated via [openDatabase]. */ operator fun invoke( @@ -128,26 +128,6 @@ class CoreCrypto(private val cc: CoreCryptoFfi) { return cc.registerHistoryObserver(observerIndirector) } - /** - * See [CoreCryptoContext.isHistorySharingEnabled] - * - * @param conversationId conversation identifier - * @return true if history sharing is enabled - */ - suspend fun isHistorySharingEnabled(conversationId: ConversationId): Boolean = cc.isHistorySharingEnabled(conversationId) - - /** - * Set the PkiEnvironment of the CoreCrypto instance - * @param pkiEnvironment the pki environment to set - */ - suspend fun setPkiEnvironment(pkiEnvironment: PkiEnvironment?) = cc.setPkiEnvironment(pkiEnvironment) - - /** - * Get the Pki Environment of the CoreCrypto instance - * @return the pki environment or null if not set - */ - suspend fun getPkiEnvironment(): PkiEnvironment? = cc.getPkiEnvironment() - /** * Closes this [CoreCrypto] instance and deallocates all loaded resources. * diff --git a/crypto-ffi/bindings/jvm/src/test/kotlin/com/wire/crypto/MLSTest.kt b/crypto-ffi/bindings/jvm/src/test/kotlin/com/wire/crypto/MLSTest.kt index 7008d215ce..912afeef85 100644 --- a/crypto-ffi/bindings/jvm/src/test/kotlin/com/wire/crypto/MLSTest.kt +++ b/crypto-ffi/bindings/jvm/src/test/kotlin/com/wire/crypto/MLSTest.kt @@ -411,6 +411,42 @@ class MLSTest : HasMockDeliveryService() { } } + @Test + fun epochObserverEvent_shouldAllowReadingData(): TestResult { + val scope = TestScope() + return scope.runTest { + val (alice) = newClients(this@MLSTest, genClientId()) + + data class ObserverEvent(val eventEpoch: ULong, val conversationEpoch: ULong) + + class Observer : EpochObserver { + val observedEvents = emptyList().toMutableList() + + override suspend fun epochChanged(conversationId: ConversationId, epoch: ULong) { + val conversationEpoch = alice.conversationEpoch(conversationId) + observedEvents.add(ObserverEvent(epoch, conversationEpoch)) + } + } + + val aliceObserver = Observer() + + alice.transaction { it.createConversationShort(id) } + val initialEpoch = alice.conversationEpoch(id) + + alice.registerEpochObserver(scope, aliceObserver) + + alice.transaction { it.updateKeyingMaterial(id) } + val laterEpoch = alice.conversationEpoch(id) + + assertEquals(initialEpoch + 1U, laterEpoch) + assertEquals(1, aliceObserver.observedEvents.size, "we triggered exactly 1 epoch change and must have observed that") + assertTrue( + aliceObserver.observedEvents.all { it.eventEpoch == it.conversationEpoch && it.eventEpoch == laterEpoch }, + "event epoch must equal the epoch read during the event" + ) + } + } + @Test fun registerHistoryObserver_should_notify_observer_on_new_secret(): TestResult { val scope = TestScope() diff --git a/crypto-ffi/src/core_crypto/e2ei/mod.rs b/crypto-ffi/src/core_crypto/e2ei/mod.rs index b7dc06ea3f..233d02096c 100644 --- a/crypto-ffi/src/core_crypto/e2ei/mod.rs +++ b/crypto-ffi/src/core_crypto/e2ei/mod.rs @@ -1,6 +1,6 @@ -use core_crypto::RecursiveError; +use core_crypto::{RecursiveError, mls::conversation::Conversation as _}; -use crate::{Ciphersuite, CoreCryptoFfi, CoreCryptoResult}; +use crate::{Ciphersuite, ConversationId, CoreCryptoFfi, CoreCryptoResult, E2eiConversationState}; pub(crate) mod identities; @@ -26,4 +26,21 @@ impl CoreCryptoFfi { .map_err(RecursiveError::mls_client("checking if e2ei is enabled")) .map_err(Into::into) } + + /// See [core_crypto::mls::conversation::Conversation::e2ei_conversation_state] + pub async fn e2ei_conversation_state( + &self, + conversation_id: &ConversationId, + ) -> CoreCryptoResult { + self.inner + .mls_session() + .await? + .get_raw_conversation(conversation_id.as_ref()) + .await + .map_err(RecursiveError::mls_client("getting conversation by id"))? + .e2ei_conversation_state() + .await + .map(Into::into) + .map_err(Into::into) + } }