Implement didRefreshTokens(): update database with updated SessionData.
This commit is contained in:
parent
8cf48986e7
commit
d293cae47f
8 changed files with 109 additions and 15 deletions
|
|
@ -40,6 +40,7 @@ import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
||||||
import io.element.android.libraries.matrix.impl.core.toProgressWatcher
|
import io.element.android.libraries.matrix.impl.core.toProgressWatcher
|
||||||
|
import io.element.android.libraries.matrix.impl.mapper.toSessionData
|
||||||
import io.element.android.libraries.matrix.impl.media.RustMediaLoader
|
import io.element.android.libraries.matrix.impl.media.RustMediaLoader
|
||||||
import io.element.android.libraries.matrix.impl.notification.RustNotificationService
|
import io.element.android.libraries.matrix.impl.notification.RustNotificationService
|
||||||
import io.element.android.libraries.matrix.impl.pushers.RustPushersService
|
import io.element.android.libraries.matrix.impl.pushers.RustPushersService
|
||||||
|
|
@ -122,7 +123,9 @@ class RustMatrixClient constructor(
|
||||||
|
|
||||||
override fun didRefreshTokens() {
|
override fun didRefreshTokens() {
|
||||||
Timber.w("didRefreshTokens()")
|
Timber.w("didRefreshTokens()")
|
||||||
// TODO handle refresh token
|
appCoroutineScope.launch {
|
||||||
|
sessionStore.updateData(client.session().toSessionData())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,18 +28,16 @@ import io.element.android.libraries.matrix.api.auth.OidcDetails
|
||||||
import io.element.android.libraries.matrix.api.core.SessionId
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrix.impl.RustMatrixClientFactory
|
import io.element.android.libraries.matrix.impl.RustMatrixClientFactory
|
||||||
import io.element.android.libraries.matrix.impl.exception.mapClientException
|
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.network.useragent.UserAgentProvider
|
||||||
import io.element.android.libraries.sessionstorage.api.SessionData
|
|
||||||
import io.element.android.libraries.sessionstorage.api.SessionStore
|
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.matrix.rustcomponents.sdk.OidcAuthenticationData
|
import org.matrix.rustcomponents.sdk.OidcAuthenticationData
|
||||||
import org.matrix.rustcomponents.sdk.Session
|
|
||||||
import org.matrix.rustcomponents.sdk.use
|
import org.matrix.rustcomponents.sdk.use
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.Date
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import org.matrix.rustcomponents.sdk.AuthenticationService as RustAuthenticationService
|
import org.matrix.rustcomponents.sdk.AuthenticationService as RustAuthenticationService
|
||||||
|
|
||||||
|
|
@ -155,14 +153,3 @@ class RustMatrixAuthenticationService @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Session.toSessionData() = SessionData(
|
|
||||||
userId = userId,
|
|
||||||
deviceId = deviceId,
|
|
||||||
accessToken = accessToken,
|
|
||||||
refreshToken = refreshToken,
|
|
||||||
homeserverUrl = homeserverUrl,
|
|
||||||
oidcData = oidcData,
|
|
||||||
slidingSyncProxy = slidingSyncProxy,
|
|
||||||
loginTimestamp = Date(),
|
|
||||||
)
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.matrix.impl.mapper
|
||||||
|
|
||||||
|
import io.element.android.libraries.sessionstorage.api.SessionData
|
||||||
|
import org.matrix.rustcomponents.sdk.Session
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
internal fun Session.toSessionData() = SessionData(
|
||||||
|
userId = userId,
|
||||||
|
deviceId = deviceId,
|
||||||
|
accessToken = accessToken,
|
||||||
|
refreshToken = refreshToken,
|
||||||
|
homeserverUrl = homeserverUrl,
|
||||||
|
oidcData = oidcData,
|
||||||
|
slidingSyncProxy = slidingSyncProxy,
|
||||||
|
loginTimestamp = Date(),
|
||||||
|
)
|
||||||
|
|
@ -23,6 +23,12 @@ interface SessionStore {
|
||||||
fun isLoggedIn(): Flow<Boolean>
|
fun isLoggedIn(): Flow<Boolean>
|
||||||
fun sessionsFlow(): Flow<List<SessionData>>
|
fun sessionsFlow(): Flow<List<SessionData>>
|
||||||
suspend fun storeData(sessionData: SessionData)
|
suspend fun storeData(sessionData: SessionData)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will update the session data matching the userId, except the value of loginTimestamp.
|
||||||
|
* No op if userId is not found in DB.
|
||||||
|
*/
|
||||||
|
suspend fun updateData(sessionData: SessionData)
|
||||||
suspend fun getSession(sessionId: String): SessionData?
|
suspend fun getSession(sessionId: String): SessionData?
|
||||||
suspend fun getAllSessions(): List<SessionData>
|
suspend fun getAllSessions(): List<SessionData>
|
||||||
suspend fun getLatestSession(): SessionData?
|
suspend fun getLatestSession(): SessionData?
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,10 @@ class InMemorySessionStore : SessionStore {
|
||||||
sessionDataFlow.value = sessionData
|
sessionDataFlow.value = sessionData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun updateData(sessionData: SessionData) {
|
||||||
|
sessionDataFlow.value = sessionData
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun getSession(sessionId: String): SessionData? {
|
override suspend fun getSession(sessionId: String): SessionData? {
|
||||||
return sessionDataFlow.value.takeIf { it?.userId == sessionId }
|
return sessionDataFlow.value.takeIf { it?.userId == sessionId }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,24 @@ class DatabaseSessionStore @Inject constructor(
|
||||||
database.sessionDataQueries.insertSessionData(sessionData.toDbModel())
|
database.sessionDataQueries.insertSessionData(sessionData.toDbModel())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun updateData(sessionData: SessionData) {
|
||||||
|
val result = database.sessionDataQueries.selectByUserId(sessionData.userId)
|
||||||
|
.executeAsOneOrNull()
|
||||||
|
?.toApiModel()
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
Timber.e("User ${sessionData.userId} not found in session database")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy new data from SDK, but keep login timestamp
|
||||||
|
database.sessionDataQueries.updateSession(
|
||||||
|
sessionData.copy(
|
||||||
|
loginTimestamp = result.loginTimestamp,
|
||||||
|
).toDbModel()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun getLatestSession(): SessionData? {
|
override suspend fun getLatestSession(): SessionData? {
|
||||||
return database.sessionDataQueries.selectFirst()
|
return database.sessionDataQueries.selectFirst()
|
||||||
.executeAsOneOrNull()
|
.executeAsOneOrNull()
|
||||||
|
|
|
||||||
|
|
@ -24,3 +24,6 @@ INSERT INTO SessionData VALUES ?;
|
||||||
|
|
||||||
removeSession:
|
removeSession:
|
||||||
DELETE FROM SessionData WHERE userId = ?;
|
DELETE FROM SessionData WHERE userId = ?;
|
||||||
|
|
||||||
|
updateSession:
|
||||||
|
REPLACE INTO SessionData VALUES ?;
|
||||||
|
|
|
||||||
|
|
@ -109,4 +109,45 @@ class DatabaseSessionStoreTests {
|
||||||
|
|
||||||
assertThat(database.sessionDataQueries.selectByUserId(aSessionData.userId).executeAsOneOrNull()).isNull()
|
assertThat(database.sessionDataQueries.selectByUserId(aSessionData.userId).executeAsOneOrNull()).isNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `update session update all fields except loginTimestamp`() = runTest {
|
||||||
|
val firstSessionData = SessionData(
|
||||||
|
userId = "userId",
|
||||||
|
deviceId = "deviceId",
|
||||||
|
accessToken = "accessToken",
|
||||||
|
refreshToken = "refreshToken",
|
||||||
|
homeserverUrl = "homeserverUrl",
|
||||||
|
slidingSyncProxy = "slidingSyncProxy",
|
||||||
|
loginTimestamp = 1,
|
||||||
|
oidcData = "aOidcData",
|
||||||
|
)
|
||||||
|
val secondSessionData = SessionData(
|
||||||
|
userId = "userId",
|
||||||
|
deviceId = "deviceIdAltered",
|
||||||
|
accessToken = "accessTokenAltered",
|
||||||
|
refreshToken = "refreshTokenAltered",
|
||||||
|
homeserverUrl = "homeserverUrlAltered",
|
||||||
|
slidingSyncProxy = "slidingSyncProxyAltered",
|
||||||
|
loginTimestamp = 2,
|
||||||
|
oidcData = "aOidcDataAltered",
|
||||||
|
)
|
||||||
|
assertThat(firstSessionData.userId).isEqualTo(secondSessionData.userId)
|
||||||
|
assertThat(firstSessionData.loginTimestamp).isNotEqualTo(secondSessionData.loginTimestamp)
|
||||||
|
|
||||||
|
database.sessionDataQueries.insertSessionData(firstSessionData)
|
||||||
|
databaseSessionStore.updateData(secondSessionData.toApiModel())
|
||||||
|
|
||||||
|
// Get the altered session
|
||||||
|
val alteredSession = databaseSessionStore.getSession(firstSessionData.userId)!!.toDbModel()
|
||||||
|
|
||||||
|
assertThat(alteredSession.userId).isEqualTo(secondSessionData.userId)
|
||||||
|
assertThat(alteredSession.deviceId).isEqualTo(secondSessionData.deviceId)
|
||||||
|
assertThat(alteredSession.accessToken).isEqualTo(secondSessionData.accessToken)
|
||||||
|
assertThat(alteredSession.refreshToken).isEqualTo(secondSessionData.refreshToken)
|
||||||
|
assertThat(alteredSession.homeserverUrl).isEqualTo(secondSessionData.homeserverUrl)
|
||||||
|
assertThat(alteredSession.slidingSyncProxy).isEqualTo(secondSessionData.slidingSyncProxy)
|
||||||
|
assertThat(alteredSession.loginTimestamp).isEqualTo(/* Not altered! */ firstSessionData.loginTimestamp)
|
||||||
|
assertThat(alteredSession.oidcData).isEqualTo(secondSessionData.oidcData)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue