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..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 @@ -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,19 @@ 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 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 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 +126,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 +145,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 +196,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 +218,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 +242,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 +259,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,