diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt index 773dbaaa07..f5c235da68 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt @@ -20,6 +20,7 @@ import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters import io.element.android.libraries.matrix.api.encryption.EncryptionService +import io.element.android.libraries.matrix.api.secretstorage.SecretStorage import io.element.android.libraries.matrix.api.linknewdevice.LinkDesktopHandler import io.element.android.libraries.matrix.api.linknewdevice.LinkMobileHandler import io.element.android.libraries.matrix.api.media.MatrixMediaLoader @@ -61,6 +62,7 @@ interface MatrixClient { val notificationService: NotificationService val notificationSettingsService: NotificationSettingsService val encryptionService: EncryptionService + val secretStorage: SecretStorage val roomDirectoryService: RoomDirectoryService val mediaPreviewService: MediaPreviewService val matrixMediaLoader: MatrixMediaLoader diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/secretstorage/SecretStorage.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/secretstorage/SecretStorage.kt new file mode 100644 index 0000000000..343f592a5d --- /dev/null +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/secretstorage/SecretStorage.kt @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2026 Sulkta Coop. + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package io.element.android.libraries.matrix.api.secretstorage + +/** + * Interface for accessing Matrix SSSS (Secure Secret Storage and Sharing). + * + * This allows storing and retrieving encrypted secrets in the user's + * Matrix account data, using their recovery key for encryption. + */ +interface SecretStorage { + /** + * Open the secret store with a recovery key. + * + * @param recoveryKey The Matrix recovery key (base58 encoded, 48 characters) + * or passphrase that was used to set up SSSS + * @return SecretStore instance if key is valid, null if invalid or SSSS not set up + */ + suspend fun openSecretStore(recoveryKey: String): SecretStore? +} + +/** + * An opened secret store that can read and write secrets. + * + * Secrets are encrypted with the recovery key and stored in the user's + * account data on the homeserver. + */ +interface SecretStore { + /** + * Store a secret encrypted with SSSS. + * + * @param secretName The secret identifier (e.g., "com.sulkta.cardano.wallet_seed") + * @param secret The secret value to store + */ + suspend fun putSecret(secretName: String, secret: String): Result + + /** + * Retrieve a secret from SSSS. + * + * @param secretName The secret identifier + * @return The decrypted secret, or null if not found + */ + suspend fun getSecret(secretName: String): Result + + /** + * Export the recovery key as a base58-encoded string. + * + * This is useful for displaying the key to the user for verification. + */ + fun exportRecoveryKey(): String +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index 1c87e73ba2..945841f148 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -49,6 +49,7 @@ import io.element.android.libraries.matrix.api.sync.SyncState import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.impl.encryption.RustEncryptionService +import io.element.android.libraries.matrix.impl.secretstorage.RustSecretStorage import io.element.android.libraries.matrix.impl.exception.mapClientException import io.element.android.libraries.matrix.impl.linknewdevice.RustLinkDesktopHandler import io.element.android.libraries.matrix.impl.linknewdevice.RustLinkMobileHandler @@ -178,6 +179,8 @@ class RustMatrixClient( dispatchers = dispatchers, ) + override val secretStorage = RustSecretStorage(innerClient, dispatchers) + override val roomDirectoryService = RustRoomDirectoryService( client = innerClient, sessionDispatcher = sessionDispatcher, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/analytics/RustAnalyticsSdkManager.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/analytics/RustAnalyticsSdkManager.kt index a74acab683..be91571efd 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/analytics/RustAnalyticsSdkManager.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/analytics/RustAnalyticsSdkManager.kt @@ -11,12 +11,12 @@ import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding import io.element.android.services.analytics.api.AnalyticsSdkManager import io.element.android.services.analytics.api.AnalyticsSdkSpan -import org.matrix.rustcomponents.sdk.enableSentryLogging @ContributesBinding(AppScope::class) class RustAnalyticsSdkManager : AnalyticsSdkManager { override fun enableSdkAnalytics(enabled: Boolean) { - enableSentryLogging(enabled) + // Sentry logging was removed from the Rust SDK + // This is now a no-op } override fun startSpan(name: String, parentTraceId: String?): AnalyticsSdkSpan { diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/secretstorage/RustSecretStorage.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/secretstorage/RustSecretStorage.kt new file mode 100644 index 0000000000..4f205bfb26 --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/secretstorage/RustSecretStorage.kt @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2026 Sulkta Coop. + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package io.element.android.libraries.matrix.impl.secretstorage + +import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.matrix.api.secretstorage.SecretStorage +import io.element.android.libraries.matrix.api.secretstorage.SecretStore +import kotlinx.coroutines.withContext +import org.matrix.rustcomponents.sdk.Client +import org.matrix.rustcomponents.sdk.SecretStoreWrapper + +/** + * Implementation of [SecretStorage] backed by the Rust SDK. + */ +class RustSecretStorage( + private val client: Client, + private val dispatchers: CoroutineDispatchers, +) : SecretStorage { + + override suspend fun openSecretStore(recoveryKey: String): SecretStore? = + withContext(dispatchers.io) { + client.openSecretStore(recoveryKey)?.let { RustSecretStore(it, dispatchers) } + } +} + +/** + * Implementation of [SecretStore] backed by the Rust SDK SecretStoreWrapper. + */ +class RustSecretStore( + private val inner: SecretStoreWrapper, + private val dispatchers: CoroutineDispatchers, +) : SecretStore { + + override suspend fun putSecret(secretName: String, secret: String): Result = + withContext(dispatchers.io) { + runCatching { inner.putSecret(secretName, secret) } + } + + override suspend fun getSecret(secretName: String): Result = + withContext(dispatchers.io) { + runCatching { inner.getSecret(secretName) } + } + + override fun exportRecoveryKey(): String = inner.exportRecoveryKey() +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/tracing/RustTracingService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/tracing/RustTracingService.kt index cad3c83443..d1c2b81612 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/tracing/RustTracingService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/tracing/RustTracingService.kt @@ -17,7 +17,6 @@ import io.element.android.libraries.matrix.api.tracing.LogLevel import io.element.android.libraries.matrix.api.tracing.TracingConfiguration import io.element.android.libraries.matrix.api.tracing.TracingService import io.element.android.libraries.matrix.api.tracing.WriteToFilesConfiguration -import org.matrix.rustcomponents.sdk.SentryConfig import org.matrix.rustcomponents.sdk.TracingFileConfiguration import org.matrix.rustcomponents.sdk.reloadTracingFileWriter import timber.log.Timber @@ -60,17 +59,14 @@ private fun WriteToFilesConfiguration.toTracingFileConfiguration(): TracingFileC } } -fun TracingConfiguration.map(buildMeta: BuildMeta): org.matrix.rustcomponents.sdk.TracingConfiguration = org.matrix.rustcomponents.sdk.TracingConfiguration( - writeToStdoutOrSystem = writesToLogcat, - logLevel = logLevel.toRustLogLevel(), - extraTargets = extraTargets, - traceLogPacks = traceLogPacks.map(), - writeToFiles = writesToFilesConfiguration.toTracingFileConfiguration(), - sentryConfig = sdkSentryDsn?.let { - SentryConfig( - dsn = it, - appVersion = buildMeta.versionName, - appPlatform = "Android", - ) - } -) +@Suppress("UNUSED_PARAMETER") +fun TracingConfiguration.map(buildMeta: BuildMeta): org.matrix.rustcomponents.sdk.TracingConfiguration { + // Note: sdkSentryDsn is no longer supported by the Rust SDK + return org.matrix.rustcomponents.sdk.TracingConfiguration( + writeToStdoutOrSystem = writesToLogcat, + logLevel = logLevel.toRustLogLevel(), + extraTargets = extraTargets, + traceLogPacks = traceLogPacks.map(), + writeToFiles = writesToFilesConfiguration.toTracingFileConfiguration(), + ) +}