From 08b5cc72617384e049f3e759c7dcf5cf29e83b88 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 12 Aug 2024 14:16:58 +0200 Subject: [PATCH 1/2] Ensure sessionPath is not reused for different homeserver. --- .../auth/RustMatrixAuthenticationService.kt | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt index e1ff0811e1..4408f59cd9 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt @@ -60,7 +60,7 @@ import javax.inject.Inject @ContributesBinding(AppScope::class) @SingleIn(AppScope::class) class RustMatrixAuthenticationService @Inject constructor( - baseDirectory: File, + private val baseDirectory: File, private val coroutineDispatchers: CoroutineDispatchers, private val sessionStore: SessionStore, private val rustMatrixClientFactory: RustMatrixClientFactory, @@ -70,10 +70,18 @@ class RustMatrixAuthenticationService @Inject constructor( // Passphrase which will be used for new sessions. Existing sessions will use the passphrase // stored in the SessionData. private val pendingPassphrase = getDatabasePassphrase() - private val sessionPath = File(baseDirectory, UUID.randomUUID().toString()).absolutePath + // Need to keep a copy of the current session path to delete it. + // Ideally it would be possible to get the sessionPath from the Client to avoid doing this. + private var sessionPath: File? = null private var currentClient: Client? = null private var currentHomeserver = MutableStateFlow(null) + private fun rotateSessionPath(): File { + sessionPath?.deleteRecursively() + return File(baseDirectory, UUID.randomUUID().toString()) + .also { sessionPath = it } + } + override fun loggedInStateFlow(): Flow { return sessionStore.isLoggedIn() } @@ -117,8 +125,9 @@ class RustMatrixAuthenticationService @Inject constructor( override suspend fun setHomeserver(homeserver: String): Result = withContext(coroutineDispatchers.io) { + val emptySessionPath = rotateSessionPath() runCatching { - val client = getBaseClientBuilder() + val client = getBaseClientBuilder(emptySessionPath) .serverNameOrHomeserverUrl(homeserver) .build() currentClient = client @@ -135,13 +144,14 @@ class RustMatrixAuthenticationService @Inject constructor( withContext(coroutineDispatchers.io) { runCatching { val client = currentClient ?: error("You need to call `setHomeserver()` first") + val currentSessionPath = sessionPath ?: error("You need to call `setHomeserver()` first") client.login(username, password, "Element X Android", null) val sessionData = client.session() .toSessionData( isTokenValid = true, loginType = LoginType.PASSWORD, passphrase = pendingPassphrase, - sessionPath = sessionPath, + sessionPath = currentSessionPath.absolutePath, ) clear() sessionStore.storeData(sessionData) @@ -185,13 +195,14 @@ class RustMatrixAuthenticationService @Inject constructor( return withContext(coroutineDispatchers.io) { runCatching { val client = currentClient ?: error("You need to call `setHomeserver()` first") + val currentSessionPath = sessionPath ?: error("You need to call `setHomeserver()` first") val urlForOidcLogin = pendingOidcAuthorizationData ?: error("You need to call `getOidcUrl()` first") client.loginWithOidcCallback(urlForOidcLogin, callbackUrl) val sessionData = client.session().toSessionData( isTokenValid = true, loginType = LoginType.OIDC, passphrase = pendingPassphrase, - sessionPath = sessionPath, + sessionPath = currentSessionPath.absolutePath, ) clear() pendingOidcAuthorizationData?.close() @@ -206,9 +217,10 @@ class RustMatrixAuthenticationService @Inject constructor( override suspend fun loginWithQrCode(qrCodeData: MatrixQrCodeLoginData, progress: (QrCodeLoginStep) -> Unit) = withContext(coroutineDispatchers.io) { + val emptySessionPath = rotateSessionPath() runCatching { val client = rustMatrixClientFactory.getBaseClientBuilder( - sessionPath = sessionPath, + sessionPath = emptySessionPath.absolutePath, passphrase = pendingPassphrase, slidingSyncProxy = AuthenticationConfig.SLIDING_SYNC_PROXY_URL, slidingSync = ClientBuilderSlidingSync.Discovered, @@ -229,7 +241,7 @@ class RustMatrixAuthenticationService @Inject constructor( isTokenValid = true, loginType = LoginType.QR, passphrase = pendingPassphrase, - sessionPath = sessionPath, + sessionPath = emptySessionPath.absolutePath, ) sessionStore.storeData(sessionData) SessionId(sessionData.userId) @@ -246,11 +258,13 @@ class RustMatrixAuthenticationService @Inject constructor( } Timber.e(throwable, "Failed to login with QR code") } - } + } - private fun getBaseClientBuilder() = rustMatrixClientFactory + private fun getBaseClientBuilder( + sessionPath: File, + ) = rustMatrixClientFactory .getBaseClientBuilder( - sessionPath = sessionPath, + sessionPath = sessionPath.absolutePath, passphrase = pendingPassphrase, slidingSyncProxy = AuthenticationConfig.SLIDING_SYNC_PROXY_URL, slidingSync = ClientBuilderSlidingSync.Discovered, From 0d5f6d3e67ba22af15c97c51b22ef5b5f605449e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 12 Aug 2024 14:55:12 +0200 Subject: [PATCH 2/2] Fix formatting and improve comment. --- .../matrix/impl/auth/RustMatrixAuthenticationService.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt index 4408f59cd9..b447dd584b 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt @@ -70,7 +70,8 @@ class RustMatrixAuthenticationService @Inject constructor( // Passphrase which will be used for new sessions. Existing sessions will use the passphrase // stored in the SessionData. private val pendingPassphrase = getDatabasePassphrase() - // Need to keep a copy of the current session path to delete it. + + // Need to keep a copy of the current session path to eventually delete it. // Ideally it would be possible to get the sessionPath from the Client to avoid doing this. private var sessionPath: File? = null private var currentClient: Client? = null