Add session path migration to SessionData
This commit is contained in:
parent
1a13a591f8
commit
841558c3b4
18 changed files with 117 additions and 41 deletions
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 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.features.migration.impl.migrations
|
||||||
|
|
||||||
|
import com.squareup.anvil.annotations.ContributesMultibinding
|
||||||
|
import io.element.android.libraries.di.AppScope
|
||||||
|
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||||
|
import java.io.File
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ContributesMultibinding(AppScope::class)
|
||||||
|
class AppMigration05 @Inject constructor(
|
||||||
|
private val sessionStore: SessionStore,
|
||||||
|
private val baseDirectory: File,
|
||||||
|
) : AppMigration {
|
||||||
|
override val order: Int = 5
|
||||||
|
|
||||||
|
override suspend fun migrate() {
|
||||||
|
val allSessions = sessionStore.getAllSessions()
|
||||||
|
for (session in allSessions) {
|
||||||
|
if (session.sessionPath.isEmpty()) {
|
||||||
|
val sessionPath = File(baseDirectory, session.userId.replace(':', '_')).absolutePath
|
||||||
|
sessionStore.updateData(session.copy(sessionPath = sessionPath))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -51,5 +51,6 @@ fun aSessionData(
|
||||||
isTokenValid = isTokenValid,
|
isTokenValid = isTokenValid,
|
||||||
loginType = LoginType.UNKNOWN,
|
loginType = LoginType.UNKNOWN,
|
||||||
passphrase = null,
|
passphrase = null,
|
||||||
|
sessionPath = "/a/path/to/a/session",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ import io.element.android.libraries.matrix.impl.roomlist.RustRoomListService
|
||||||
import io.element.android.libraries.matrix.impl.sync.RustSyncService
|
import io.element.android.libraries.matrix.impl.sync.RustSyncService
|
||||||
import io.element.android.libraries.matrix.impl.usersearch.UserProfileMapper
|
import io.element.android.libraries.matrix.impl.usersearch.UserProfileMapper
|
||||||
import io.element.android.libraries.matrix.impl.usersearch.UserSearchResultMapper
|
import io.element.android.libraries.matrix.impl.usersearch.UserSearchResultMapper
|
||||||
import io.element.android.libraries.matrix.impl.util.SessionDirectoryNameProvider
|
import io.element.android.libraries.matrix.impl.util.SessionDirectoryProvider
|
||||||
import io.element.android.libraries.matrix.impl.util.cancelAndDestroy
|
import io.element.android.libraries.matrix.impl.util.cancelAndDestroy
|
||||||
import io.element.android.libraries.matrix.impl.util.mxCallbackFlow
|
import io.element.android.libraries.matrix.impl.util.mxCallbackFlow
|
||||||
import io.element.android.libraries.matrix.impl.verification.RustSessionVerificationService
|
import io.element.android.libraries.matrix.impl.verification.RustSessionVerificationService
|
||||||
|
|
@ -151,7 +151,7 @@ class RustMatrixClient(
|
||||||
sessionDispatcher = sessionDispatcher,
|
sessionDispatcher = sessionDispatcher,
|
||||||
)
|
)
|
||||||
|
|
||||||
private val sessionDirectoryNameProvider = SessionDirectoryNameProvider()
|
private val sessionDirectoryProvider = SessionDirectoryProvider(sessionStore)
|
||||||
|
|
||||||
private val isLoggingOut = AtomicBoolean(false)
|
private val isLoggingOut = AtomicBoolean(false)
|
||||||
|
|
||||||
|
|
@ -171,6 +171,7 @@ class RustMatrixClient(
|
||||||
isTokenValid = false,
|
isTokenValid = false,
|
||||||
loginType = existingData.loginType,
|
loginType = existingData.loginType,
|
||||||
passphrase = existingData.passphrase,
|
passphrase = existingData.passphrase,
|
||||||
|
sessionPath = existingData.sessionPath,
|
||||||
)
|
)
|
||||||
sessionStore.updateData(newData)
|
sessionStore.updateData(newData)
|
||||||
Timber.d("Removed session data with token: '...$anonymizedToken'.")
|
Timber.d("Removed session data with token: '...$anonymizedToken'.")
|
||||||
|
|
@ -198,6 +199,7 @@ class RustMatrixClient(
|
||||||
isTokenValid = true,
|
isTokenValid = true,
|
||||||
loginType = existingData.loginType,
|
loginType = existingData.loginType,
|
||||||
passphrase = existingData.passphrase,
|
passphrase = existingData.passphrase,
|
||||||
|
sessionPath = existingData.sessionPath,
|
||||||
)
|
)
|
||||||
sessionStore.updateData(newData)
|
sessionStore.updateData(newData)
|
||||||
Timber.d("Saved new session data with token: '...$anonymizedToken'.")
|
Timber.d("Saved new session data with token: '...$anonymizedToken'.")
|
||||||
|
|
@ -482,7 +484,7 @@ class RustMatrixClient(
|
||||||
|
|
||||||
override suspend fun clearCache() {
|
override suspend fun clearCache() {
|
||||||
close()
|
close()
|
||||||
baseDirectory.deleteSessionDirectory(deleteCryptoDb = false)
|
deleteSessionDirectory(deleteCryptoDb = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun logout(ignoreSdkError: Boolean): String? = doLogout(
|
override suspend fun logout(ignoreSdkError: Boolean): String? = doLogout(
|
||||||
|
|
@ -512,7 +514,7 @@ class RustMatrixClient(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close()
|
close()
|
||||||
baseDirectory.deleteSessionDirectory(deleteCryptoDb = true)
|
deleteSessionDirectory(deleteCryptoDb = true)
|
||||||
if (removeSession) {
|
if (removeSession) {
|
||||||
sessionStore.removeSession(sessionId.value)
|
sessionStore.removeSession(sessionId.value)
|
||||||
}
|
}
|
||||||
|
|
@ -554,8 +556,7 @@ class RustMatrixClient(
|
||||||
private suspend fun File.getCacheSize(
|
private suspend fun File.getCacheSize(
|
||||||
includeCryptoDb: Boolean = false,
|
includeCryptoDb: Boolean = false,
|
||||||
): Long = withContext(sessionDispatcher) {
|
): Long = withContext(sessionDispatcher) {
|
||||||
val sessionDirectoryName = sessionDirectoryNameProvider.provides(sessionId)
|
val sessionDirectory = sessionDirectoryProvider.provides(sessionId) ?: return@withContext 0L
|
||||||
val sessionDirectory = File(this@getCacheSize, sessionDirectoryName)
|
|
||||||
if (includeCryptoDb) {
|
if (includeCryptoDb) {
|
||||||
sessionDirectory.getSizeOfFiles()
|
sessionDirectory.getSizeOfFiles()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -571,11 +572,10 @@ class RustMatrixClient(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun File.deleteSessionDirectory(
|
private suspend fun deleteSessionDirectory(
|
||||||
deleteCryptoDb: Boolean = false,
|
deleteCryptoDb: Boolean = false,
|
||||||
): Boolean = withContext(sessionDispatcher) {
|
): Boolean = withContext(sessionDispatcher) {
|
||||||
val sessionDirectoryName = sessionDirectoryNameProvider.provides(sessionId)
|
val sessionDirectory = sessionDirectoryProvider.provides(sessionId) ?: return@withContext false
|
||||||
val sessionDirectory = File(this@deleteSessionDirectory, sessionDirectoryName)
|
|
||||||
if (deleteCryptoDb) {
|
if (deleteCryptoDb) {
|
||||||
// Delete the folder and all its content
|
// Delete the folder and all its content
|
||||||
sessionDirectory.deleteRecursively()
|
sessionDirectory.deleteRecursively()
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ class RustMatrixClientFactory @Inject constructor(
|
||||||
private val utdTracker: UtdTracker,
|
private val utdTracker: UtdTracker,
|
||||||
) {
|
) {
|
||||||
suspend fun create(sessionData: SessionData): RustMatrixClient = withContext(coroutineDispatchers.io) {
|
suspend fun create(sessionData: SessionData): RustMatrixClient = withContext(coroutineDispatchers.io) {
|
||||||
val client = getBaseClientBuilder()
|
val client = getBaseClientBuilder(sessionData.sessionPath)
|
||||||
.homeserverUrl(sessionData.homeserverUrl)
|
.homeserverUrl(sessionData.homeserverUrl)
|
||||||
.username(sessionData.userId)
|
.username(sessionData.userId)
|
||||||
.passphrase(sessionData.passphrase)
|
.passphrase(sessionData.passphrase)
|
||||||
|
|
@ -71,9 +71,9 @@ class RustMatrixClientFactory @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun getBaseClientBuilder(): ClientBuilder {
|
internal fun getBaseClientBuilder(sessionPath: String): ClientBuilder {
|
||||||
return ClientBuilder()
|
return ClientBuilder()
|
||||||
.basePath(baseDirectory.absolutePath)
|
.sessionPath(sessionPath)
|
||||||
.userAgent(userAgentProvider.provide())
|
.userAgent(userAgentProvider.provide())
|
||||||
.addRootCertificates(userCertificatesProvider.provides())
|
.addRootCertificates(userCertificatesProvider.provides())
|
||||||
.serverVersions(listOf("v1.0", "v1.1", "v1.2", "v1.3", "v1.4", "v1.5"))
|
.serverVersions(listOf("v1.0", "v1.1", "v1.2", "v1.3", "v1.4", "v1.5"))
|
||||||
|
|
|
||||||
|
|
@ -18,19 +18,26 @@ package io.element.android.libraries.matrix.impl.auth
|
||||||
|
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcConfig
|
import io.element.android.libraries.matrix.api.auth.OidcConfig
|
||||||
import org.matrix.rustcomponents.sdk.OidcConfiguration
|
import org.matrix.rustcomponents.sdk.OidcConfiguration
|
||||||
|
import java.io.File
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
val oidcConfiguration: OidcConfiguration = OidcConfiguration(
|
class OidConfigurationProvider @Inject constructor(
|
||||||
clientName = "Element",
|
private val baseDirectory: File,
|
||||||
redirectUri = OidcConfig.REDIRECT_URI,
|
) {
|
||||||
clientUri = "https://element.io",
|
fun get(): OidcConfiguration = OidcConfiguration(
|
||||||
logoUri = "https://element.io/mobile-icon.png",
|
clientName = "Element",
|
||||||
tosUri = "https://element.io/acceptable-use-policy-terms",
|
redirectUri = OidcConfig.REDIRECT_URI,
|
||||||
policyUri = "https://element.io/privacy",
|
clientUri = "https://element.io",
|
||||||
contacts = listOf(
|
logoUri = "https://element.io/mobile-icon.png",
|
||||||
"support@element.io",
|
tosUri = "https://element.io/acceptable-use-policy-terms",
|
||||||
),
|
policyUri = "https://element.io/privacy",
|
||||||
// Some homeservers/auth issuers don't support dynamic client registration, and have to be registered manually
|
contacts = listOf(
|
||||||
staticRegistrations = mapOf(
|
"support@element.io",
|
||||||
"https://id.thirdroom.io/realms/thirdroom" to "elementx",
|
),
|
||||||
),
|
// Some homeservers/auth issuers don't support dynamic client registration, and have to be registered manually
|
||||||
)
|
staticRegistrations = mapOf(
|
||||||
|
"https://id.thirdroom.io/realms/thirdroom" to "elementx",
|
||||||
|
),
|
||||||
|
dynamicRegistrationsFile = File(baseDirectory, "oidc/registrations.json").absolutePath,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ import org.matrix.rustcomponents.sdk.QrLoginProgressListener
|
||||||
import org.matrix.rustcomponents.sdk.use
|
import org.matrix.rustcomponents.sdk.use
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.util.UUID
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import org.matrix.rustcomponents.sdk.AuthenticationService as RustAuthenticationService
|
import org.matrix.rustcomponents.sdk.AuthenticationService as RustAuthenticationService
|
||||||
|
|
||||||
|
|
@ -68,17 +69,19 @@ class RustMatrixAuthenticationService @Inject constructor(
|
||||||
private val passphraseGenerator: PassphraseGenerator,
|
private val passphraseGenerator: PassphraseGenerator,
|
||||||
userCertificatesProvider: UserCertificatesProvider,
|
userCertificatesProvider: UserCertificatesProvider,
|
||||||
proxyProvider: ProxyProvider,
|
proxyProvider: ProxyProvider,
|
||||||
|
private val oidConfigurationProvider: OidConfigurationProvider,
|
||||||
) : MatrixAuthenticationService {
|
) : MatrixAuthenticationService {
|
||||||
// Passphrase which will be used for new sessions. Existing sessions will use the passphrase
|
// Passphrase which will be used for new sessions. Existing sessions will use the passphrase
|
||||||
// stored in the SessionData.
|
// stored in the SessionData.
|
||||||
private val pendingPassphrase = getDatabasePassphrase()
|
private val pendingPassphrase = getDatabasePassphrase()
|
||||||
|
private val sessionPath = File(baseDirectory, UUID.randomUUID().toString()).absolutePath
|
||||||
private val authService: RustAuthenticationService = RustAuthenticationService(
|
private val authService: RustAuthenticationService = RustAuthenticationService(
|
||||||
basePath = baseDirectory.absolutePath,
|
sessionPath = sessionPath,
|
||||||
passphrase = pendingPassphrase,
|
passphrase = pendingPassphrase,
|
||||||
proxy = proxyProvider.provides(),
|
proxy = proxyProvider.provides(),
|
||||||
userAgent = userAgentProvider.provide(),
|
userAgent = userAgentProvider.provide(),
|
||||||
additionalRootCertificates = userCertificatesProvider.provides(),
|
additionalRootCertificates = userCertificatesProvider.provides(),
|
||||||
oidcConfiguration = oidcConfiguration,
|
oidcConfiguration = oidConfigurationProvider.get(),
|
||||||
customSlidingSyncProxy = null,
|
customSlidingSyncProxy = null,
|
||||||
sessionDelegate = null,
|
sessionDelegate = null,
|
||||||
crossProcessRefreshLockId = null,
|
crossProcessRefreshLockId = null,
|
||||||
|
|
@ -148,6 +151,7 @@ class RustMatrixAuthenticationService @Inject constructor(
|
||||||
isTokenValid = true,
|
isTokenValid = true,
|
||||||
loginType = LoginType.PASSWORD,
|
loginType = LoginType.PASSWORD,
|
||||||
passphrase = pendingPassphrase,
|
passphrase = pendingPassphrase,
|
||||||
|
sessionPath = sessionPath,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
sessionStore.storeData(sessionData)
|
sessionStore.storeData(sessionData)
|
||||||
|
|
@ -196,6 +200,7 @@ class RustMatrixAuthenticationService @Inject constructor(
|
||||||
isTokenValid = true,
|
isTokenValid = true,
|
||||||
loginType = LoginType.OIDC,
|
loginType = LoginType.OIDC,
|
||||||
passphrase = pendingPassphrase,
|
passphrase = pendingPassphrase,
|
||||||
|
sessionPath = sessionPath,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
pendingOidcAuthenticationData?.close()
|
pendingOidcAuthenticationData?.close()
|
||||||
|
|
@ -211,11 +216,11 @@ class RustMatrixAuthenticationService @Inject constructor(
|
||||||
override suspend fun loginWithQrCode(qrCodeData: MatrixQrCodeLoginData, progress: (QrCodeLoginStep) -> Unit) =
|
override suspend fun loginWithQrCode(qrCodeData: MatrixQrCodeLoginData, progress: (QrCodeLoginStep) -> Unit) =
|
||||||
withContext(coroutineDispatchers.io) {
|
withContext(coroutineDispatchers.io) {
|
||||||
runCatching {
|
runCatching {
|
||||||
val client = rustMatrixClientFactory.getBaseClientBuilder()
|
val client = rustMatrixClientFactory.getBaseClientBuilder(sessionPath)
|
||||||
.passphrase(pendingPassphrase)
|
.passphrase(pendingPassphrase)
|
||||||
.buildWithQrCode(
|
.buildWithQrCode(
|
||||||
qrCodeData = (qrCodeData as SdkQrCodeLoginData).rustQrCodeData,
|
qrCodeData = (qrCodeData as SdkQrCodeLoginData).rustQrCodeData,
|
||||||
oidcConfiguration = oidcConfiguration,
|
oidcConfiguration = oidConfigurationProvider.get(),
|
||||||
progressListener = object : QrLoginProgressListener {
|
progressListener = object : QrLoginProgressListener {
|
||||||
override fun onUpdate(state: QrLoginProgress) {
|
override fun onUpdate(state: QrLoginProgress) {
|
||||||
Timber.d("QR Code login progress: $state")
|
Timber.d("QR Code login progress: $state")
|
||||||
|
|
@ -229,6 +234,7 @@ class RustMatrixAuthenticationService @Inject constructor(
|
||||||
isTokenValid = true,
|
isTokenValid = true,
|
||||||
loginType = LoginType.QR,
|
loginType = LoginType.QR,
|
||||||
passphrase = pendingPassphrase,
|
passphrase = pendingPassphrase,
|
||||||
|
sessionPath = sessionPath,
|
||||||
)
|
)
|
||||||
sessionStore.storeData(sessionData)
|
sessionStore.storeData(sessionData)
|
||||||
SessionId(sessionData.userId)
|
SessionId(sessionData.userId)
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ internal fun Session.toSessionData(
|
||||||
isTokenValid: Boolean,
|
isTokenValid: Boolean,
|
||||||
loginType: LoginType,
|
loginType: LoginType,
|
||||||
passphrase: String?,
|
passphrase: String?,
|
||||||
|
sessionPath: String,
|
||||||
) = SessionData(
|
) = SessionData(
|
||||||
userId = userId,
|
userId = userId,
|
||||||
deviceId = deviceId,
|
deviceId = deviceId,
|
||||||
|
|
@ -37,4 +38,5 @@ internal fun Session.toSessionData(
|
||||||
isTokenValid = isTokenValid,
|
isTokenValid = isTokenValid,
|
||||||
loginType = loginType,
|
loginType = loginType,
|
||||||
passphrase = passphrase,
|
passphrase = passphrase,
|
||||||
|
sessionPath = sessionPath,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -265,6 +265,7 @@ class RustTimeline(
|
||||||
messageEventContentFromParts(body, htmlBody).withMentions(mentions.map()).use { content ->
|
messageEventContentFromParts(body, htmlBody).withMentions(mentions.map()).use { content ->
|
||||||
runCatching {
|
runCatching {
|
||||||
inner.send(content)
|
inner.send(content)
|
||||||
|
Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -292,6 +293,7 @@ class RustTimeline(
|
||||||
runCatching {
|
runCatching {
|
||||||
transactionId?.let { cancelSend(it) }
|
transactionId?.let { cancelSend(it) }
|
||||||
inner.send(messageEventContentFromParts(body, htmlBody))
|
inner.send(messageEventContentFromParts(body, htmlBody))
|
||||||
|
Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -412,13 +414,13 @@ class RustTimeline(
|
||||||
|
|
||||||
override suspend fun retrySendMessage(transactionId: TransactionId): Result<Unit> = withContext(dispatcher) {
|
override suspend fun retrySendMessage(transactionId: TransactionId): Result<Unit> = withContext(dispatcher) {
|
||||||
runCatching {
|
runCatching {
|
||||||
inner.retrySend(transactionId.value)
|
// inner.retrySend(transactionId.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun cancelSend(transactionId: TransactionId): Result<Unit> = withContext(dispatcher) {
|
override suspend fun cancelSend(transactionId: TransactionId): Result<Unit> = withContext(dispatcher) {
|
||||||
runCatching {
|
runCatching {
|
||||||
inner.cancelSend(transactionId.value)
|
// inner.cancelSend(transactionId.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,6 @@ fun RustEventSendState?.map(): LocalEventSendState? {
|
||||||
RustEventSendState.NotSentYet -> LocalEventSendState.NotSentYet
|
RustEventSendState.NotSentYet -> LocalEventSendState.NotSentYet
|
||||||
is RustEventSendState.SendingFailed -> LocalEventSendState.SendingFailed(error)
|
is RustEventSendState.SendingFailed -> LocalEventSendState.SendingFailed(error)
|
||||||
is RustEventSendState.Sent -> LocalEventSendState.Sent(EventId(eventId))
|
is RustEventSendState.Sent -> LocalEventSendState.Sent(EventId(eventId))
|
||||||
RustEventSendState.Cancelled -> LocalEventSendState.Canceled
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ class TimelineEventContentMapper(private val eventMessageMapper: EventMessageMap
|
||||||
StickerContent(
|
StickerContent(
|
||||||
body = kind.body,
|
body = kind.body,
|
||||||
info = kind.info.map(),
|
info = kind.info.map(),
|
||||||
url = kind.url,
|
url = kind.source.url(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is TimelineItemContentKind.Poll -> {
|
is TimelineItemContentKind.Poll -> {
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,15 @@
|
||||||
package io.element.android.libraries.matrix.impl.util
|
package io.element.android.libraries.matrix.impl.util
|
||||||
|
|
||||||
import io.element.android.libraries.matrix.api.core.SessionId
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
|
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||||
|
import java.io.File
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
class SessionDirectoryNameProvider {
|
class SessionDirectoryProvider @Inject constructor(
|
||||||
// Rust sanitises the user ID replacing invalid characters with an _
|
private val sessionStore: SessionStore,
|
||||||
fun provides(sessionId: SessionId): String {
|
) {
|
||||||
return sessionId.value.replace(":", "_")
|
suspend fun provides(sessionId: SessionId): File? {
|
||||||
|
val path = sessionStore.getSession(sessionId.value)?.sessionPath ?: return null
|
||||||
|
return File(path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -44,4 +44,6 @@ data class SessionData(
|
||||||
val loginType: LoginType,
|
val loginType: LoginType,
|
||||||
/** The optional passphrase used to encrypt data in the SDK local store. */
|
/** The optional passphrase used to encrypt data in the SDK local store. */
|
||||||
val passphrase: String?,
|
val passphrase: String?,
|
||||||
|
/** The path to the session data stored in the filesystem. */
|
||||||
|
val sessionPath: String,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ internal fun SessionData.toDbModel(): DbSessionData {
|
||||||
isTokenValid = if (isTokenValid) 1L else 0L,
|
isTokenValid = if (isTokenValid) 1L else 0L,
|
||||||
loginType = loginType.name,
|
loginType = loginType.name,
|
||||||
passphrase = passphrase,
|
passphrase = passphrase,
|
||||||
|
sessionPath = sessionPath,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,5 +51,6 @@ internal fun DbSessionData.toApiModel(): SessionData {
|
||||||
isTokenValid = isTokenValid == 1L,
|
isTokenValid = isTokenValid == 1L,
|
||||||
loginType = LoginType.fromName(loginType ?: LoginType.UNKNOWN.name),
|
loginType = LoginType.fromName(loginType ?: LoginType.UNKNOWN.name),
|
||||||
passphrase = passphrase,
|
passphrase = passphrase,
|
||||||
|
sessionPath = sessionPath,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,9 @@ import io.element.encrypteddb.passphrase.RandomSecretPassphraseProvider
|
||||||
object SessionStorageModule {
|
object SessionStorageModule {
|
||||||
@Provides
|
@Provides
|
||||||
@SingleIn(AppScope::class)
|
@SingleIn(AppScope::class)
|
||||||
fun provideMatrixDatabase(@ApplicationContext context: Context): SessionDatabase {
|
fun provideMatrixDatabase(
|
||||||
|
@ApplicationContext context: Context,
|
||||||
|
): SessionDatabase {
|
||||||
val name = "session_database"
|
val name = "session_database"
|
||||||
val secretFile = context.getDatabasePath("$name.key")
|
val secretFile = context.getDatabasePath("$name.key")
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -23,7 +23,9 @@ CREATE TABLE SessionData (
|
||||||
isTokenValid INTEGER NOT NULL DEFAULT 1,
|
isTokenValid INTEGER NOT NULL DEFAULT 1,
|
||||||
loginType TEXT,
|
loginType TEXT,
|
||||||
-- added in version 5
|
-- added in version 5
|
||||||
passphrase TEXT
|
passphrase TEXT,
|
||||||
|
-- added in version 6
|
||||||
|
sessionPath TEXT NOT NULL DEFAULT ""
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
-- Migrate DB from version 7
|
||||||
|
-- Add sessionPath so we can track the anonymized path for the session files dir
|
||||||
|
|
||||||
|
ALTER TABLE SessionData ADD COLUMN sessionPath TEXT NOT NULL DEFAULT "";
|
||||||
|
|
@ -36,5 +36,6 @@ fun aSessionData(
|
||||||
isTokenValid = isTokenValid,
|
isTokenValid = isTokenValid,
|
||||||
loginType = LoginType.UNKNOWN,
|
loginType = LoginType.UNKNOWN,
|
||||||
passphrase = null,
|
passphrase = null,
|
||||||
|
sessionPath = "/a/path/to/a/session",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue