feat(matrix): add SecretStorage API and implementation

Adds SecretStorage interface and RustSecretStorage implementation
for accessing Matrix SSSS (Secure Secret Storage and Sharing).

This enables storing and retrieving encrypted secrets using the
user's recovery key.

Also fixes SDK compatibility issues:
- Remove deprecated Sentry configuration from TracingService
- Make analytics SDK enableSentryLogging a no-op

Requires updated Rust SDK with SecretStoreWrapper FFI.
This commit is contained in:
Kayos 2026-03-28 17:18:05 -07:00
parent f56f124a39
commit 86d6686aee
6 changed files with 122 additions and 17 deletions

View file

@ -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,

View file

@ -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 {

View file

@ -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<Unit> =
withContext(dispatchers.io) {
runCatching { inner.putSecret(secretName, secret) }
}
override suspend fun getSecret(secretName: String): Result<String?> =
withContext(dispatchers.io) {
runCatching { inner.getSecret(secretName) }
}
override fun exportRecoveryKey(): String = inner.exportRecoveryKey()
}

View file

@ -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(),
)
}