Browse Source

Implement didRefreshTokens(): update database with updated SessionData.

pull/1127/head
Benoit Marty 1 year ago
parent
commit
d293cae47f
  1. 5
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt
  2. 15
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt
  3. 32
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/mapper/Session.kt
  4. 6
      libraries/session-storage/api/src/main/kotlin/io/element/android/libraries/sessionstorage/api/SessionStore.kt
  5. 4
      libraries/session-storage/impl-memory/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/memory/InMemorySessionStore.kt
  6. 18
      libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStore.kt
  7. 3
      libraries/session-storage/impl/src/main/sqldelight/io/element/android/libraries/matrix/session/SessionData.sq
  8. 41
      libraries/session-storage/impl/src/test/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStoreTests.kt

5
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt

@ -40,6 +40,7 @@ import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults @@ -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.verification.SessionVerificationService
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.notification.RustNotificationService
import io.element.android.libraries.matrix.impl.pushers.RustPushersService
@ -122,7 +123,9 @@ class RustMatrixClient constructor( @@ -122,7 +123,9 @@ class RustMatrixClient constructor(
override fun didRefreshTokens() {
Timber.w("didRefreshTokens()")
// TODO handle refresh token
appCoroutineScope.launch {
sessionStore.updateData(client.session().toSessionData())
}
}
}

15
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt

@ -28,18 +28,16 @@ import io.element.android.libraries.matrix.api.auth.OidcDetails @@ -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.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.SessionData
import io.element.android.libraries.sessionstorage.api.SessionStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.OidcAuthenticationData
import org.matrix.rustcomponents.sdk.Session
import org.matrix.rustcomponents.sdk.use
import java.io.File
import java.util.Date
import javax.inject.Inject
import org.matrix.rustcomponents.sdk.AuthenticationService as RustAuthenticationService
@ -155,14 +153,3 @@ class RustMatrixAuthenticationService @Inject constructor( @@ -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(),
)

32
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/mapper/Session.kt

@ -0,0 +1,32 @@ @@ -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(),
)

6
libraries/session-storage/api/src/main/kotlin/io/element/android/libraries/sessionstorage/api/SessionStore.kt

@ -23,6 +23,12 @@ interface SessionStore { @@ -23,6 +23,12 @@ interface SessionStore {
fun isLoggedIn(): Flow<Boolean>
fun sessionsFlow(): Flow<List<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 getAllSessions(): List<SessionData>
suspend fun getLatestSession(): SessionData?

4
libraries/session-storage/impl-memory/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/memory/InMemorySessionStore.kt

@ -38,6 +38,10 @@ class InMemorySessionStore : SessionStore { @@ -38,6 +38,10 @@ class InMemorySessionStore : SessionStore {
sessionDataFlow.value = sessionData
}
override suspend fun updateData(sessionData: SessionData) {
sessionDataFlow.value = sessionData
}
override suspend fun getSession(sessionId: String): SessionData? {
return sessionDataFlow.value.takeIf { it?.userId == sessionId }
}

18
libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStore.kt

@ -46,6 +46,24 @@ class DatabaseSessionStore @Inject constructor( @@ -46,6 +46,24 @@ class DatabaseSessionStore @Inject constructor(
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? {
return database.sessionDataQueries.selectFirst()
.executeAsOneOrNull()

3
libraries/session-storage/impl/src/main/sqldelight/io/element/android/libraries/matrix/session/SessionData.sq

@ -24,3 +24,6 @@ INSERT INTO SessionData VALUES ?; @@ -24,3 +24,6 @@ INSERT INTO SessionData VALUES ?;
removeSession:
DELETE FROM SessionData WHERE userId = ?;
updateSession:
REPLACE INTO SessionData VALUES ?;

41
libraries/session-storage/impl/src/test/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStoreTests.kt

@ -109,4 +109,45 @@ class DatabaseSessionStoreTests { @@ -109,4 +109,45 @@ class DatabaseSessionStoreTests {
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…
Cancel
Save