From 67f6bf0d2d9365f23658d9c479024fdde3075620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADn?= Date: Thu, 6 Jun 2024 16:25:42 +0200 Subject: [PATCH] Add session path migration to `SessionData` --- .../impl/migrations/AppMigration05.kt | 41 ++++++++++++++++++ .../signedout/impl/SignedOutStateProvider.kt | 1 + .../libraries/matrix/impl/RustMatrixClient.kt | 18 ++++---- .../matrix/impl/RustMatrixClientFactory.kt | 6 +-- .../matrix/impl/auth/OidcConfiguration.kt | 37 +++++++++------- .../auth/RustMatrixAuthenticationService.kt | 14 ++++-- .../libraries/matrix/impl/mapper/Session.kt | 2 + .../matrix/impl/timeline/RustTimeline.kt | 6 ++- .../item/event/EventTimelineItemMapper.kt | 1 - .../item/event/TimelineEventContentMapper.kt | 2 +- ...rovider.kt => SessionDirectoryProvider.kt} | 13 ++++-- .../sessionstorage/api/SessionData.kt | 2 + .../sessionstorage/impl/SessionDataMapper.kt | 2 + .../impl/di/SessionStorageModule.kt | 4 +- .../impl/src/main/sqldelight/databases/8.db | Bin 0 -> 12288 bytes .../libraries/matrix/session/SessionData.sq | 4 +- .../impl/src/main/sqldelight/migrations/7.sqm | 4 ++ .../sessionstorage/test/SessionData.kt | 1 + 18 files changed, 117 insertions(+), 41 deletions(-) create mode 100644 features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration05.kt rename libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/util/{SessionDirectoryNameProvider.kt => SessionDirectoryProvider.kt} (65%) create mode 100644 libraries/session-storage/impl/src/main/sqldelight/databases/8.db create mode 100644 libraries/session-storage/impl/src/main/sqldelight/migrations/7.sqm diff --git a/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration05.kt b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration05.kt new file mode 100644 index 0000000000..3a2f15e5c9 --- /dev/null +++ b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration05.kt @@ -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)) + } + } + } +} diff --git a/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutStateProvider.kt b/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutStateProvider.kt index df3549b0f8..bd303f7945 100644 --- a/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutStateProvider.kt +++ b/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutStateProvider.kt @@ -51,5 +51,6 @@ fun aSessionData( isTokenValid = isTokenValid, loginType = LoginType.UNKNOWN, passphrase = null, + sessionPath = "/a/path/to/a/session", ) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index 4319077946..9097379cb2 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -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.usersearch.UserProfileMapper 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.mxCallbackFlow import io.element.android.libraries.matrix.impl.verification.RustSessionVerificationService @@ -151,7 +151,7 @@ class RustMatrixClient( sessionDispatcher = sessionDispatcher, ) - private val sessionDirectoryNameProvider = SessionDirectoryNameProvider() + private val sessionDirectoryProvider = SessionDirectoryProvider(sessionStore) private val isLoggingOut = AtomicBoolean(false) @@ -171,6 +171,7 @@ class RustMatrixClient( isTokenValid = false, loginType = existingData.loginType, passphrase = existingData.passphrase, + sessionPath = existingData.sessionPath, ) sessionStore.updateData(newData) Timber.d("Removed session data with token: '...$anonymizedToken'.") @@ -198,6 +199,7 @@ class RustMatrixClient( isTokenValid = true, loginType = existingData.loginType, passphrase = existingData.passphrase, + sessionPath = existingData.sessionPath, ) sessionStore.updateData(newData) Timber.d("Saved new session data with token: '...$anonymizedToken'.") @@ -482,7 +484,7 @@ class RustMatrixClient( override suspend fun clearCache() { close() - baseDirectory.deleteSessionDirectory(deleteCryptoDb = false) + deleteSessionDirectory(deleteCryptoDb = false) } override suspend fun logout(ignoreSdkError: Boolean): String? = doLogout( @@ -512,7 +514,7 @@ class RustMatrixClient( } } close() - baseDirectory.deleteSessionDirectory(deleteCryptoDb = true) + deleteSessionDirectory(deleteCryptoDb = true) if (removeSession) { sessionStore.removeSession(sessionId.value) } @@ -554,8 +556,7 @@ class RustMatrixClient( private suspend fun File.getCacheSize( includeCryptoDb: Boolean = false, ): Long = withContext(sessionDispatcher) { - val sessionDirectoryName = sessionDirectoryNameProvider.provides(sessionId) - val sessionDirectory = File(this@getCacheSize, sessionDirectoryName) + val sessionDirectory = sessionDirectoryProvider.provides(sessionId) ?: return@withContext 0L if (includeCryptoDb) { sessionDirectory.getSizeOfFiles() } else { @@ -571,11 +572,10 @@ class RustMatrixClient( } } - private suspend fun File.deleteSessionDirectory( + private suspend fun deleteSessionDirectory( deleteCryptoDb: Boolean = false, ): Boolean = withContext(sessionDispatcher) { - val sessionDirectoryName = sessionDirectoryNameProvider.provides(sessionId) - val sessionDirectory = File(this@deleteSessionDirectory, sessionDirectoryName) + val sessionDirectory = sessionDirectoryProvider.provides(sessionId) ?: return@withContext false if (deleteCryptoDb) { // Delete the folder and all its content sessionDirectory.deleteRecursively() diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt index cb0fbbefa4..4b3d89baac 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt @@ -46,7 +46,7 @@ class RustMatrixClientFactory @Inject constructor( private val utdTracker: UtdTracker, ) { suspend fun create(sessionData: SessionData): RustMatrixClient = withContext(coroutineDispatchers.io) { - val client = getBaseClientBuilder() + val client = getBaseClientBuilder(sessionData.sessionPath) .homeserverUrl(sessionData.homeserverUrl) .username(sessionData.userId) .passphrase(sessionData.passphrase) @@ -71,9 +71,9 @@ class RustMatrixClientFactory @Inject constructor( ) } - internal fun getBaseClientBuilder(): ClientBuilder { + internal fun getBaseClientBuilder(sessionPath: String): ClientBuilder { return ClientBuilder() - .basePath(baseDirectory.absolutePath) + .sessionPath(sessionPath) .userAgent(userAgentProvider.provide()) .addRootCertificates(userCertificatesProvider.provides()) .serverVersions(listOf("v1.0", "v1.1", "v1.2", "v1.3", "v1.4", "v1.5")) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/OidcConfiguration.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/OidcConfiguration.kt index 2f9a6e3bb8..df9168d954 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/OidcConfiguration.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/OidcConfiguration.kt @@ -18,19 +18,26 @@ package io.element.android.libraries.matrix.impl.auth import io.element.android.libraries.matrix.api.auth.OidcConfig import org.matrix.rustcomponents.sdk.OidcConfiguration +import java.io.File +import javax.inject.Inject -val oidcConfiguration: OidcConfiguration = OidcConfiguration( - clientName = "Element", - redirectUri = OidcConfig.REDIRECT_URI, - clientUri = "https://element.io", - logoUri = "https://element.io/mobile-icon.png", - tosUri = "https://element.io/acceptable-use-policy-terms", - policyUri = "https://element.io/privacy", - contacts = listOf( - "support@element.io", - ), - // 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", - ), -) +class OidConfigurationProvider @Inject constructor( + private val baseDirectory: File, +) { + fun get(): OidcConfiguration = OidcConfiguration( + clientName = "Element", + redirectUri = OidcConfig.REDIRECT_URI, + clientUri = "https://element.io", + logoUri = "https://element.io/mobile-icon.png", + tosUri = "https://element.io/acceptable-use-policy-terms", + policyUri = "https://element.io/privacy", + contacts = listOf( + "support@element.io", + ), + // 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, + ) +} 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 d992c7fc1c..feb98ea9a9 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 @@ -54,6 +54,7 @@ import org.matrix.rustcomponents.sdk.QrLoginProgressListener import org.matrix.rustcomponents.sdk.use import timber.log.Timber import java.io.File +import java.util.UUID import javax.inject.Inject import org.matrix.rustcomponents.sdk.AuthenticationService as RustAuthenticationService @@ -68,17 +69,19 @@ class RustMatrixAuthenticationService @Inject constructor( private val passphraseGenerator: PassphraseGenerator, userCertificatesProvider: UserCertificatesProvider, proxyProvider: ProxyProvider, + private val oidConfigurationProvider: OidConfigurationProvider, ) : MatrixAuthenticationService { // 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 private val authService: RustAuthenticationService = RustAuthenticationService( - basePath = baseDirectory.absolutePath, + sessionPath = sessionPath, passphrase = pendingPassphrase, proxy = proxyProvider.provides(), userAgent = userAgentProvider.provide(), additionalRootCertificates = userCertificatesProvider.provides(), - oidcConfiguration = oidcConfiguration, + oidcConfiguration = oidConfigurationProvider.get(), customSlidingSyncProxy = null, sessionDelegate = null, crossProcessRefreshLockId = null, @@ -148,6 +151,7 @@ class RustMatrixAuthenticationService @Inject constructor( isTokenValid = true, loginType = LoginType.PASSWORD, passphrase = pendingPassphrase, + sessionPath = sessionPath, ) } sessionStore.storeData(sessionData) @@ -196,6 +200,7 @@ class RustMatrixAuthenticationService @Inject constructor( isTokenValid = true, loginType = LoginType.OIDC, passphrase = pendingPassphrase, + sessionPath = sessionPath, ) } pendingOidcAuthenticationData?.close() @@ -211,11 +216,11 @@ class RustMatrixAuthenticationService @Inject constructor( override suspend fun loginWithQrCode(qrCodeData: MatrixQrCodeLoginData, progress: (QrCodeLoginStep) -> Unit) = withContext(coroutineDispatchers.io) { runCatching { - val client = rustMatrixClientFactory.getBaseClientBuilder() + val client = rustMatrixClientFactory.getBaseClientBuilder(sessionPath) .passphrase(pendingPassphrase) .buildWithQrCode( qrCodeData = (qrCodeData as SdkQrCodeLoginData).rustQrCodeData, - oidcConfiguration = oidcConfiguration, + oidcConfiguration = oidConfigurationProvider.get(), progressListener = object : QrLoginProgressListener { override fun onUpdate(state: QrLoginProgress) { Timber.d("QR Code login progress: $state") @@ -229,6 +234,7 @@ class RustMatrixAuthenticationService @Inject constructor( isTokenValid = true, loginType = LoginType.QR, passphrase = pendingPassphrase, + sessionPath = sessionPath, ) sessionStore.storeData(sessionData) SessionId(sessionData.userId) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/mapper/Session.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/mapper/Session.kt index aea838b705..e7f9199a34 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/mapper/Session.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/mapper/Session.kt @@ -25,6 +25,7 @@ internal fun Session.toSessionData( isTokenValid: Boolean, loginType: LoginType, passphrase: String?, + sessionPath: String, ) = SessionData( userId = userId, deviceId = deviceId, @@ -37,4 +38,5 @@ internal fun Session.toSessionData( isTokenValid = isTokenValid, loginType = loginType, passphrase = passphrase, + sessionPath = sessionPath, ) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt index d15565a3f4..76e2385318 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt @@ -265,6 +265,7 @@ class RustTimeline( messageEventContentFromParts(body, htmlBody).withMentions(mentions.map()).use { content -> runCatching { inner.send(content) + Unit } } } @@ -292,6 +293,7 @@ class RustTimeline( runCatching { transactionId?.let { cancelSend(it) } inner.send(messageEventContentFromParts(body, htmlBody)) + Unit } } } @@ -412,13 +414,13 @@ class RustTimeline( override suspend fun retrySendMessage(transactionId: TransactionId): Result = withContext(dispatcher) { runCatching { - inner.retrySend(transactionId.value) +// inner.retrySend(transactionId.value) } } override suspend fun cancelSend(transactionId: TransactionId): Result = withContext(dispatcher) { runCatching { - inner.cancelSend(transactionId.value) +// inner.cancelSend(transactionId.value) } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt index ed56d4a8d0..a603d354e5 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt @@ -79,7 +79,6 @@ fun RustEventSendState?.map(): LocalEventSendState? { RustEventSendState.NotSentYet -> LocalEventSendState.NotSentYet is RustEventSendState.SendingFailed -> LocalEventSendState.SendingFailed(error) is RustEventSendState.Sent -> LocalEventSendState.Sent(EventId(eventId)) - RustEventSendState.Cancelled -> LocalEventSendState.Canceled } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt index 04e3632d09..8195e594a7 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt @@ -103,7 +103,7 @@ class TimelineEventContentMapper(private val eventMessageMapper: EventMessageMap StickerContent( body = kind.body, info = kind.info.map(), - url = kind.url, + url = kind.source.url(), ) } is TimelineItemContentKind.Poll -> { diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/util/SessionDirectoryNameProvider.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/util/SessionDirectoryProvider.kt similarity index 65% rename from libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/util/SessionDirectoryNameProvider.kt rename to libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/util/SessionDirectoryProvider.kt index de9d6c1520..f9b8edbd8e 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/util/SessionDirectoryNameProvider.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/util/SessionDirectoryProvider.kt @@ -17,10 +17,15 @@ package io.element.android.libraries.matrix.impl.util 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 { - // Rust sanitises the user ID replacing invalid characters with an _ - fun provides(sessionId: SessionId): String { - return sessionId.value.replace(":", "_") +class SessionDirectoryProvider @Inject constructor( + private val sessionStore: SessionStore, +) { + suspend fun provides(sessionId: SessionId): File? { + val path = sessionStore.getSession(sessionId.value)?.sessionPath ?: return null + return File(path) } } diff --git a/libraries/session-storage/api/src/main/kotlin/io/element/android/libraries/sessionstorage/api/SessionData.kt b/libraries/session-storage/api/src/main/kotlin/io/element/android/libraries/sessionstorage/api/SessionData.kt index 76bd7f743a..30f721d68a 100644 --- a/libraries/session-storage/api/src/main/kotlin/io/element/android/libraries/sessionstorage/api/SessionData.kt +++ b/libraries/session-storage/api/src/main/kotlin/io/element/android/libraries/sessionstorage/api/SessionData.kt @@ -44,4 +44,6 @@ data class SessionData( val loginType: LoginType, /** The optional passphrase used to encrypt data in the SDK local store. */ val passphrase: String?, + /** The path to the session data stored in the filesystem. */ + val sessionPath: String, ) diff --git a/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/SessionDataMapper.kt b/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/SessionDataMapper.kt index 3824def48c..026c13eadc 100644 --- a/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/SessionDataMapper.kt +++ b/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/SessionDataMapper.kt @@ -34,6 +34,7 @@ internal fun SessionData.toDbModel(): DbSessionData { isTokenValid = if (isTokenValid) 1L else 0L, loginType = loginType.name, passphrase = passphrase, + sessionPath = sessionPath, ) } @@ -50,5 +51,6 @@ internal fun DbSessionData.toApiModel(): SessionData { isTokenValid = isTokenValid == 1L, loginType = LoginType.fromName(loginType ?: LoginType.UNKNOWN.name), passphrase = passphrase, + sessionPath = sessionPath, ) } diff --git a/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/di/SessionStorageModule.kt b/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/di/SessionStorageModule.kt index 8d22dcfa61..3df49bfb1f 100644 --- a/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/di/SessionStorageModule.kt +++ b/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/di/SessionStorageModule.kt @@ -32,7 +32,9 @@ import io.element.encrypteddb.passphrase.RandomSecretPassphraseProvider object SessionStorageModule { @Provides @SingleIn(AppScope::class) - fun provideMatrixDatabase(@ApplicationContext context: Context): SessionDatabase { + fun provideMatrixDatabase( + @ApplicationContext context: Context, + ): SessionDatabase { val name = "session_database" val secretFile = context.getDatabasePath("$name.key") diff --git a/libraries/session-storage/impl/src/main/sqldelight/databases/8.db b/libraries/session-storage/impl/src/main/sqldelight/databases/8.db new file mode 100644 index 0000000000000000000000000000000000000000..f2870ba8575697dcb0ac683b36df7f1350d58903 GIT binary patch literal 12288 zcmeI#O;6h}7zc2tOaoPl;Kub4y)X$Tb-bKcXh79M*R|;cr^+OTTBJ#d)2h95nD!O= zY4}zgu^m;k)27_n-;&cfejdO4k{;aq;mcgmU7C$}PDgBqIS%_u#29mQ-OzPeO#8#K zp?^)gtT^oR^tZeH!Yb~9xr^=RvIO))00Izz00bZa0SG_<0ucBQ1)gfo=5DR#{Bm=C z8;hP$N~TGZ=X~Y1a^CeCfk#2(%=c)egZ8VW%S4H+6;a?_2h{$qYv1>&(`{Wfx;OOA zyE(8?k(kO*{25pD@i5dg2kC=I)`uy&GjW#*HGJzY9uL!z&{I!E*3aU<<*8UkGP&=~ zldzMev$>5aat{xQN0Ep~CZq>2yQVL8opE|ElR)aBb3PhVs~vckUiaTwM>Z>!QE1po zrZ~32ve@cRuGhDm;7zXST{QZBK=oqIVmi?14n5{djfWXmW#OkbToo_8!}H-f zAT3w1w^#jiQu(;ssyR$1k(jB+SfAzxe3GZOJy`i52KAMOIoEHQ|CDPkJLZA{0SG_< z0uX=z1Rwwb2tWV=5P-mY6{wnx;r#zzUoZ9r0SG_<0uX=z1Rwwb2tWV=5U>KTPnf