Merge pull request #1520 from vector-im/feature/bma/sessionDb

Improve session db and improve deleted session behavior
This commit is contained in:
Benoit Marty 2023-10-11 16:56:54 +02:00 committed by GitHub
commit 88ca37984f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 968 additions and 49 deletions

View file

@ -18,12 +18,18 @@ package io.element.android.libraries.matrix.api.auth
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.sessionstorage.api.LoggedInState
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
interface MatrixAuthenticationService {
fun isLoggedIn(): Flow<Boolean>
fun loggedInStateFlow(): Flow<LoggedInState>
suspend fun getLatestSessionId(): SessionId?
/**
* Restore a session from a [sessionId].
* Do not restore anything it the access token is not valid anymore.
*/
suspend fun restoreSession(sessionId: SessionId): Result<MatrixClient>
fun getHomeserverDetails(): StateFlow<MatrixHomeServerDetails?>
suspend fun setHomeserver(homeserver: String): Result<Unit>

View file

@ -126,7 +126,16 @@ class RustMatrixClient constructor(
Timber.v("didReceiveAuthError -> do the cleanup")
//TODO handle isSoftLogout parameter.
appCoroutineScope.launch {
doLogout(doRequest = false)
val existingData = sessionStore.getSession(client.userId())
if (existingData != null) {
// Set isTokenValid to false
val newData = client.session().toSessionData(
isTokenValid = false,
loginType = existingData.loginType,
)
sessionStore.updateData(newData)
}
doLogout(doRequest = false, removeSession = false)
}
} else {
Timber.v("didReceiveAuthError -> already cleaning up")
@ -136,7 +145,12 @@ class RustMatrixClient constructor(
override fun didRefreshTokens() {
Timber.w("didRefreshTokens()")
appCoroutineScope.launch {
sessionStore.updateData(client.session().toSessionData())
val existingData = sessionStore.getSession(client.userId()) ?: return@launch
val newData = client.session().toSessionData(
isTokenValid = existingData.isTokenValid,
loginType = existingData.loginType,
)
sessionStore.updateData(newData)
}
}
}
@ -328,9 +342,9 @@ class RustMatrixClient constructor(
baseDirectory.deleteSessionDirectory(userID = sessionId.value, deleteCryptoDb = false)
}
override suspend fun logout(): String? = doLogout(doRequest = true)
override suspend fun logout(): String? = doLogout(doRequest = true, removeSession = true)
private suspend fun doLogout(doRequest: Boolean): String? {
private suspend fun doLogout(doRequest: Boolean, removeSession: Boolean): String? {
var result: String? = null
withContext(sessionDispatcher) {
if (doRequest) {
@ -342,7 +356,9 @@ class RustMatrixClient constructor(
}
close()
baseDirectory.deleteSessionDirectory(userID = sessionId.value, deleteCryptoDb = true)
sessionStore.removeSession(sessionId.value)
if (removeSession) {
sessionStore.removeSession(sessionId.value)
}
}
return result
}

View file

@ -30,6 +30,8 @@ import io.element.android.libraries.matrix.impl.RustMatrixClientFactory
import io.element.android.libraries.matrix.impl.exception.mapClientException
import io.element.android.libraries.matrix.impl.mapper.toSessionData
import io.element.android.libraries.network.useragent.UserAgentProvider
import io.element.android.libraries.sessionstorage.api.LoggedInState
import io.element.android.libraries.sessionstorage.api.LoginType
import io.element.android.libraries.sessionstorage.api.SessionStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@ -62,7 +64,7 @@ class RustMatrixAuthenticationService @Inject constructor(
)
private var currentHomeserver = MutableStateFlow<MatrixHomeServerDetails?>(null)
override fun isLoggedIn(): Flow<Boolean> {
override fun loggedInStateFlow(): Flow<LoggedInState> {
return sessionStore.isLoggedIn()
}
@ -74,7 +76,11 @@ class RustMatrixAuthenticationService @Inject constructor(
runCatching {
val sessionData = sessionStore.getSession(sessionId.value)
if (sessionData != null) {
rustMatrixClientFactory.create(sessionData)
if (sessionData.isTokenValid) {
rustMatrixClientFactory.create(sessionData)
} else {
error("Token is not valid")
}
} else {
error("No session to restore with id $sessionId")
}
@ -102,7 +108,12 @@ class RustMatrixAuthenticationService @Inject constructor(
withContext(coroutineDispatchers.io) {
runCatching {
val client = authService.login(username, password, "Element X Android", null)
val sessionData = client.use { it.session().toSessionData() }
val sessionData = client.use {
it.session().toSessionData(
isTokenValid = true,
loginType = LoginType.PASSWORD,
)
}
sessionStore.storeData(sessionData)
SessionId(sessionData.userId)
}.mapFailure { failure ->
@ -144,7 +155,12 @@ class RustMatrixAuthenticationService @Inject constructor(
runCatching {
val urlForOidcLogin = pendingOidcAuthenticationData ?: error("You need to call `getOidcUrl()` first")
val client = authService.loginWithOidcCallback(urlForOidcLogin, callbackUrl)
val sessionData = client.use { it.session().toSessionData() }
val sessionData = client.use {
it.session().toSessionData(
isTokenValid = true,
loginType = LoginType.OIDC,
)
}
pendingOidcAuthenticationData?.close()
pendingOidcAuthenticationData = null
sessionStore.storeData(sessionData)

View file

@ -16,11 +16,15 @@
package io.element.android.libraries.matrix.impl.mapper
import io.element.android.libraries.sessionstorage.api.LoginType
import io.element.android.libraries.sessionstorage.api.SessionData
import org.matrix.rustcomponents.sdk.Session
import java.util.Date
internal fun Session.toSessionData() = SessionData(
internal fun Session.toSessionData(
isTokenValid: Boolean,
loginType: LoginType,
) = SessionData(
userId = userId,
deviceId = deviceId,
accessToken = accessToken,
@ -29,4 +33,6 @@ internal fun Session.toSessionData() = SessionData(
oidcData = oidcData,
slidingSyncProxy = slidingSyncProxy,
loginTimestamp = Date(),
isTokenValid = isTokenValid,
loginType = loginType,
)

View file

@ -22,6 +22,7 @@ import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails
import io.element.android.libraries.matrix.api.auth.OidcDetails
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.libraries.sessionstorage.api.LoggedInState
import io.element.android.tests.testutils.simulateLongTask
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@ -38,8 +39,8 @@ class FakeAuthenticationService : MatrixAuthenticationService {
private var changeServerError: Throwable? = null
private var matrixClient: MatrixClient? = null
override fun isLoggedIn(): Flow<Boolean> {
return flowOf(false)
override fun loggedInStateFlow(): Flow<LoggedInState> {
return flowOf(LoggedInState.NotLoggedIn)
}
override suspend fun getLatestSessionId(): SessionId? {