From d78ed70e0f0f08bc73adaeee96aa8fb6a3945ee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=8B=D1=82=D0=BA=D0=BE=D0=B2=20=D0=A0=D0=BE=D0=BC?= =?UTF-8?q?=D0=B0=D0=BD?= Date: Sat, 25 Jan 2025 20:19:06 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9C=D0=B5=D1=82=D0=B0=20=D0=B8=D0=BD=D1=84?= =?UTF-8?q?=D0=BE=D1=80=D0=BC=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BE=20=D1=85?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=B8=D0=BB=D0=B8=D1=89=D0=B0=D1=85=20=D1=85?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=B8=D1=82=D1=81=D1=8F=20=D0=B2=20=D0=B1?= =?UTF-8?q?=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wallenc/app/ExampleInstrumentedTest.kt | 2 +- .../wallenc/app/di/modules/data/RoomModule.kt | 7 ++ .../app/di/modules/data/SingletonModule.kt | 38 ++++++-- .../app/di/modules/domain/UseCasesModule.kt | 1 - .../nullptroma/wallenc/data/db/app/AppDb.kt | 6 +- .../data/db/app/dao/StorageKeyMapDao.kt | 6 +- .../data/db/app/dao/StorageMetaInfoDao.kt | 35 +++++++ .../data/db/app/model/DbStorageKeyMap.kt | 12 +-- .../data/db/app/model/DbStorageMetaInfo.kt | 13 +++ .../app/repository/StorageKeyMapRepository.kt | 14 ++- .../repository/StorageMetaInfoRepository.kt | 52 ++++++++++ .../{vaults => storages}/UnlockManager.kt | 21 ++-- .../data/storages/encrypt/EncryptedStorage.kt | 96 +++++++++++++++++++ .../encrypt/EncryptedStorageAccessor.kt | 3 +- .../local/LocalStorage.kt | 65 +++++++------ .../local/LocalStorageAccessor.kt | 12 +-- .../data/vaults/{local => }/LocalVault.kt | 3 +- .../wallenc/data/vaults/VaultsManager.kt | 1 - .../common/impl/CommonStorageMetaInfo.kt | 7 +- .../domain/encrypt/EncryptedStorage.kt | 52 ---------- .../wallenc/domain/interfaces/IStorage.kt | 3 + .../wallenc/domain/interfaces/IStorageInfo.kt | 1 + .../domain/interfaces/IStorageMetaInfo.kt | 4 +- gradle/libs.versions.toml | 5 +- .../screens/local/vault/LocalVaultScreen.kt | 4 +- 25 files changed, 328 insertions(+), 135 deletions(-) create mode 100644 data/src/main/java/com/github/nullptroma/wallenc/data/db/app/dao/StorageMetaInfoDao.kt create mode 100644 data/src/main/java/com/github/nullptroma/wallenc/data/db/app/model/DbStorageMetaInfo.kt create mode 100644 data/src/main/java/com/github/nullptroma/wallenc/data/db/app/repository/StorageMetaInfoRepository.kt rename data/src/main/java/com/github/nullptroma/wallenc/data/{vaults => storages}/UnlockManager.kt (82%) create mode 100644 data/src/main/java/com/github/nullptroma/wallenc/data/storages/encrypt/EncryptedStorage.kt rename {domain/src/main/java/com/github/nullptroma/wallenc/domain => data/src/main/java/com/github/nullptroma/wallenc/data/storages}/encrypt/EncryptedStorageAccessor.kt (98%) rename data/src/main/java/com/github/nullptroma/wallenc/data/{vaults => storages}/local/LocalStorage.kt (55%) rename data/src/main/java/com/github/nullptroma/wallenc/data/{vaults => storages}/local/LocalStorageAccessor.kt (98%) rename data/src/main/java/com/github/nullptroma/wallenc/data/vaults/{local => }/LocalVault.kt (96%) delete mode 100644 domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/EncryptedStorage.kt diff --git a/app/src/androidTest/java/com/github/nullptroma/wallenc/app/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/github/nullptroma/wallenc/app/ExampleInstrumentedTest.kt index 3a63d74..7747c1d 100644 --- a/app/src/androidTest/java/com/github/nullptroma/wallenc/app/ExampleInstrumentedTest.kt +++ b/app/src/androidTest/java/com/github/nullptroma/wallenc/app/ExampleInstrumentedTest.kt @@ -19,6 +19,6 @@ class ExampleInstrumentedTest { fun useAppContext() { // Context of the app under test. val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.github.nullptroma.wallenc", appContext.packageName) + assertEquals("com.github.nullptroma.wallenc.app", appContext.packageName) } } \ No newline at end of file diff --git a/app/src/main/java/com/github/nullptroma/wallenc/app/di/modules/data/RoomModule.kt b/app/src/main/java/com/github/nullptroma/wallenc/app/di/modules/data/RoomModule.kt index bea9206..a998fd4 100644 --- a/app/src/main/java/com/github/nullptroma/wallenc/app/di/modules/data/RoomModule.kt +++ b/app/src/main/java/com/github/nullptroma/wallenc/app/di/modules/data/RoomModule.kt @@ -4,6 +4,7 @@ import android.content.Context import com.github.nullptroma.wallenc.data.db.RoomFactory import com.github.nullptroma.wallenc.data.db.app.IAppDb import com.github.nullptroma.wallenc.data.db.app.dao.StorageKeyMapDao +import com.github.nullptroma.wallenc.data.db.app.dao.StorageMetaInfoDao import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -25,6 +26,12 @@ class RoomModule { return database.storageKeyMapDao } + @Provides + @Singleton + fun provideStorageMetaInfoDao(database: IAppDb): StorageMetaInfoDao { + return database.storageMetaInfoDao + } + @Provides @Singleton fun provideAppDb( diff --git a/app/src/main/java/com/github/nullptroma/wallenc/app/di/modules/data/SingletonModule.kt b/app/src/main/java/com/github/nullptroma/wallenc/app/di/modules/data/SingletonModule.kt index 204ba4c..8de3143 100644 --- a/app/src/main/java/com/github/nullptroma/wallenc/app/di/modules/data/SingletonModule.kt +++ b/app/src/main/java/com/github/nullptroma/wallenc/app/di/modules/data/SingletonModule.kt @@ -3,8 +3,10 @@ package com.github.nullptroma.wallenc.app.di.modules.data import android.content.Context import com.github.nullptroma.wallenc.app.di.modules.app.IoDispatcher import com.github.nullptroma.wallenc.data.db.app.dao.StorageKeyMapDao +import com.github.nullptroma.wallenc.data.db.app.dao.StorageMetaInfoDao import com.github.nullptroma.wallenc.data.db.app.repository.StorageKeyMapRepository -import com.github.nullptroma.wallenc.data.vaults.UnlockManager +import com.github.nullptroma.wallenc.data.db.app.repository.StorageMetaInfoRepository +import com.github.nullptroma.wallenc.data.storages.UnlockManager import com.github.nullptroma.wallenc.data.vaults.VaultsManager import com.github.nullptroma.wallenc.domain.interfaces.IUnlockManager import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager @@ -21,24 +23,42 @@ import javax.inject.Singleton class SingletonModule { @Provides @Singleton - fun provideVaultsManager(@IoDispatcher ioDispatcher: CoroutineDispatcher, - @ApplicationContext context: Context): IVaultsManager { + fun provideVaultsManager( + @IoDispatcher ioDispatcher: CoroutineDispatcher, + @ApplicationContext context: Context + ): IVaultsManager { return VaultsManager(ioDispatcher, context) } @Provides @Singleton - fun provideStorageKeyMapRepository(dao: StorageKeyMapDao): StorageKeyMapRepository { - return StorageKeyMapRepository(dao) + fun provideStorageKeyMapRepository( + dao: StorageKeyMapDao, + @IoDispatcher ioDispatcher: CoroutineDispatcher + ): StorageKeyMapRepository { + return StorageKeyMapRepository(dao, ioDispatcher) } @Provides @Singleton - fun provideUnlockManager(@IoDispatcher ioDispatcher: CoroutineDispatcher, - repo: StorageKeyMapRepository, - vaultsManager: IVaultsManager): IUnlockManager { + fun provideStorageMetaInfoRepository( + dao: StorageMetaInfoDao, + @IoDispatcher ioDispatcher: CoroutineDispatcher + ): StorageMetaInfoRepository { + return StorageMetaInfoRepository(dao, ioDispatcher) + } + + @Provides + @Singleton + fun provideUnlockManager( + @IoDispatcher ioDispatcher: CoroutineDispatcher, + keyRepo: StorageKeyMapRepository, + metaRepo: StorageMetaInfoRepository, + vaultsManager: IVaultsManager + ): IUnlockManager { return UnlockManager( - repo = repo, + keymapRepository = keyRepo, + metaInfoRepository = metaRepo, ioDispatcher = ioDispatcher, vaultsManager = vaultsManager ) diff --git a/app/src/main/java/com/github/nullptroma/wallenc/app/di/modules/domain/UseCasesModule.kt b/app/src/main/java/com/github/nullptroma/wallenc/app/di/modules/domain/UseCasesModule.kt index 4da7808..e16b72f 100644 --- a/app/src/main/java/com/github/nullptroma/wallenc/app/di/modules/domain/UseCasesModule.kt +++ b/app/src/main/java/com/github/nullptroma/wallenc/app/di/modules/domain/UseCasesModule.kt @@ -1,6 +1,5 @@ package com.github.nullptroma.wallenc.app.di.modules.domain -import com.github.nullptroma.wallenc.data.vaults.UnlockManager import com.github.nullptroma.wallenc.domain.interfaces.IUnlockManager import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager import com.github.nullptroma.wallenc.domain.usecases.GetOpenedStoragesUseCase diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/AppDb.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/AppDb.kt index bd48ce4..ed6cdc9 100644 --- a/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/AppDb.kt +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/AppDb.kt @@ -3,13 +3,17 @@ package com.github.nullptroma.wallenc.data.db.app import androidx.room.Database import androidx.room.RoomDatabase import com.github.nullptroma.wallenc.data.db.app.dao.StorageKeyMapDao +import com.github.nullptroma.wallenc.data.db.app.dao.StorageMetaInfoDao import com.github.nullptroma.wallenc.data.db.app.model.DbStorageKeyMap +import com.github.nullptroma.wallenc.data.db.app.model.DbStorageMetaInfo interface IAppDb { val storageKeyMapDao: StorageKeyMapDao + val storageMetaInfoDao: StorageMetaInfoDao } -@Database(entities = [DbStorageKeyMap::class], version = 2, exportSchema = false) +@Database(entities = [DbStorageKeyMap::class, DbStorageMetaInfo::class], version = 2, exportSchema = false) abstract class AppDb : IAppDb, RoomDatabase() { abstract override val storageKeyMapDao: StorageKeyMapDao + abstract override val storageMetaInfoDao: StorageMetaInfoDao } \ No newline at end of file diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/dao/StorageKeyMapDao.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/dao/StorageKeyMapDao.kt index d24e3cf..4b16379 100644 --- a/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/dao/StorageKeyMapDao.kt +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/dao/StorageKeyMapDao.kt @@ -12,11 +12,11 @@ import kotlinx.coroutines.flow.StateFlow @Dao interface StorageKeyMapDao { @Insert(onConflict = OnConflictStrategy.REPLACE) - fun add(keymap: DbStorageKeyMap) + suspend fun add(keymap: DbStorageKeyMap) @Query("SELECT * FROM storage_key_maps") - fun getAll(): List + suspend fun getAll(): List @Delete - fun delete(keymap: DbStorageKeyMap) + suspend fun delete(keymap: DbStorageKeyMap) } \ No newline at end of file diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/dao/StorageMetaInfoDao.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/dao/StorageMetaInfoDao.kt new file mode 100644 index 0000000..70d2380 --- /dev/null +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/dao/StorageMetaInfoDao.kt @@ -0,0 +1,35 @@ +package com.github.nullptroma.wallenc.data.db.app.dao + +import androidx.lifecycle.LiveData +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import com.github.nullptroma.wallenc.data.db.app.model.DbStorageKeyMap +import com.github.nullptroma.wallenc.data.db.app.model.DbStorageMetaInfo +import com.github.nullptroma.wallenc.domain.common.impl.CommonStorageMetaInfo +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.StateFlow +import java.util.UUID + +@Dao +interface StorageMetaInfoDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun add(metaInfo: DbStorageMetaInfo) + + @Query("SELECT * FROM storage_meta_infos") + suspend fun getAll(): List + + @Query("SELECT * FROM storage_meta_infos") + fun getAllFlow(): Flow> + + @Query("SELECT * FROM storage_meta_infos WHERE uuid == :uuid") + fun getMetaInfoFlow(uuid: UUID): Flow + + @Query("SELECT * FROM storage_meta_infos WHERE uuid == :uuid") + suspend fun getMetaInfo(uuid: UUID): DbStorageMetaInfo? + + @Delete + suspend fun delete(metaInfo: DbStorageMetaInfo) +} \ No newline at end of file diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/model/DbStorageKeyMap.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/model/DbStorageKeyMap.kt index a334be8..d081ba4 100644 --- a/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/model/DbStorageKeyMap.kt +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/model/DbStorageKeyMap.kt @@ -9,14 +9,14 @@ import java.util.UUID @Entity(tableName = "storage_key_maps", primaryKeys = [ "source_uuid", "dest_uuid" ]) data class DbStorageKeyMap( - @ColumnInfo(name = "source_uuid") val sourceUuid: String, - @ColumnInfo(name = "dest_uuid") val destUuid: String, + @ColumnInfo(name = "source_uuid") val sourceUuid: UUID, + @ColumnInfo(name = "dest_uuid") val destUuid: UUID, @ColumnInfo(name = "key") val key: ByteArray ) { fun toModel(): StorageKeyMap { return StorageKeyMap( - sourceUuid = UUID.fromString(sourceUuid), - destUuid = UUID.fromString(destUuid), + sourceUuid = sourceUuid, + destUuid = destUuid, key = EncryptKey(key) ) } @@ -44,8 +44,8 @@ data class DbStorageKeyMap( companion object { fun fromModel(keymap: StorageKeyMap): DbStorageKeyMap { return DbStorageKeyMap( - sourceUuid = keymap.sourceUuid.toString(), - destUuid = keymap.destUuid.toString(), + sourceUuid = keymap.sourceUuid, + destUuid = keymap.destUuid, key = keymap.key.bytes ) } diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/model/DbStorageMetaInfo.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/model/DbStorageMetaInfo.kt new file mode 100644 index 0000000..f63dc42 --- /dev/null +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/model/DbStorageMetaInfo.kt @@ -0,0 +1,13 @@ +package com.github.nullptroma.wallenc.data.db.app.model + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.github.nullptroma.wallenc.domain.common.impl.CommonStorageMetaInfo +import java.util.UUID + +@Entity(tableName = "storage_meta_infos") +data class DbStorageMetaInfo( + @PrimaryKey @ColumnInfo(name = "uuid") val uuid: UUID, + @ColumnInfo(name = "meta_info") val metaInfoJson: String +) \ No newline at end of file diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/repository/StorageKeyMapRepository.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/repository/StorageKeyMapRepository.kt index 0afb48c..3efcf3d 100644 --- a/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/repository/StorageKeyMapRepository.kt +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/repository/StorageKeyMapRepository.kt @@ -3,14 +3,20 @@ package com.github.nullptroma.wallenc.data.db.app.repository import com.github.nullptroma.wallenc.data.db.app.dao.StorageKeyMapDao import com.github.nullptroma.wallenc.data.db.app.model.DbStorageKeyMap import com.github.nullptroma.wallenc.data.model.StorageKeyMap +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.withContext -class StorageKeyMapRepository(private val dao: StorageKeyMapDao) { - fun getAll() = dao.getAll().map { it.toModel() } - fun add(keymap: StorageKeyMap) { +class StorageKeyMapRepository( + private val dao: StorageKeyMapDao, + private val ioDispatcher: CoroutineDispatcher +) { + suspend fun getAll() = withContext(ioDispatcher) { dao.getAll().map { it.toModel() } } + suspend fun add(keymap: StorageKeyMap) = withContext(ioDispatcher) { val dbModel = DbStorageKeyMap.fromModel(keymap) dao.add(dbModel) } - fun delete(keymap: StorageKeyMap) { + + suspend fun delete(keymap: StorageKeyMap) = withContext(ioDispatcher) { val dbModel = DbStorageKeyMap.fromModel(keymap) dao.delete(dbModel) } diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/repository/StorageMetaInfoRepository.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/repository/StorageMetaInfoRepository.kt new file mode 100644 index 0000000..872bf1b --- /dev/null +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/repository/StorageMetaInfoRepository.kt @@ -0,0 +1,52 @@ +package com.github.nullptroma.wallenc.data.db.app.repository + +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.github.nullptroma.wallenc.data.db.app.dao.StorageMetaInfoDao +import com.github.nullptroma.wallenc.data.db.app.model.DbStorageMetaInfo +import com.github.nullptroma.wallenc.domain.common.impl.CommonStorageMetaInfo +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.withContext +import java.util.UUID + +class StorageMetaInfoRepository( + private val dao: StorageMetaInfoDao, + private val ioDispatcher: CoroutineDispatcher +) { + fun getAllFlow() = dao.getAllFlow() + suspend fun getAll() = withContext(ioDispatcher) { dao.getAll() } + suspend fun getMeta(uuid: UUID): CommonStorageMetaInfo? = withContext(ioDispatcher) { + val json = dao.getMetaInfo(uuid)?.metaInfoJson ?: return@withContext null + return@withContext jackson.readValue( + json, + CommonStorageMetaInfo::class.java + ) + } + + fun observeMeta(uuid: UUID): Flow { + return dao.getMetaInfoFlow(uuid) + .map { jackson.readValue(it.metaInfoJson, CommonStorageMetaInfo::class.java) } + } + + suspend fun setMeta(uuid: UUID, metaInfo: CommonStorageMetaInfo) = withContext(ioDispatcher) { + val json = jackson.writeValueAsString(metaInfo) + dao.add(DbStorageMetaInfo(uuid, json)) + } + + fun createSingleStorageProvider(uuid: UUID): SingleStorageMetaInfoProvider { + return SingleStorageMetaInfoProvider(this, uuid) + } + + class SingleStorageMetaInfoProvider ( + private val repo: StorageMetaInfoRepository, + val uuid: UUID + ) { + suspend fun get(): CommonStorageMetaInfo? = repo.getMeta(uuid) + suspend fun set(metaInfo: CommonStorageMetaInfo) = repo.setMeta(uuid, metaInfo) + } + + companion object { + private val jackson = jacksonObjectMapper().apply { findAndRegisterModules() } + } +} \ No newline at end of file diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/UnlockManager.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/storages/UnlockManager.kt similarity index 82% rename from data/src/main/java/com/github/nullptroma/wallenc/data/vaults/UnlockManager.kt rename to data/src/main/java/com/github/nullptroma/wallenc/data/storages/UnlockManager.kt index 7c1fa92..0e60af4 100644 --- a/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/UnlockManager.kt +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/storages/UnlockManager.kt @@ -1,9 +1,10 @@ -package com.github.nullptroma.wallenc.data.vaults +package com.github.nullptroma.wallenc.data.storages import com.github.nullptroma.wallenc.data.db.app.repository.StorageKeyMapRepository +import com.github.nullptroma.wallenc.data.db.app.repository.StorageMetaInfoRepository import com.github.nullptroma.wallenc.data.model.StorageKeyMap import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey -import com.github.nullptroma.wallenc.domain.encrypt.EncryptedStorage +import com.github.nullptroma.wallenc.data.storages.encrypt.EncryptedStorage import com.github.nullptroma.wallenc.domain.encrypt.Encryptor import com.github.nullptroma.wallenc.domain.interfaces.IStorage import com.github.nullptroma.wallenc.domain.interfaces.IUnlockManager @@ -20,7 +21,8 @@ import kotlinx.coroutines.withContext import java.util.UUID class UnlockManager( - private val repo: StorageKeyMapRepository, + private val keymapRepository: StorageKeyMapRepository, + private val metaInfoRepository: StorageMetaInfoRepository, private val ioDispatcher: CoroutineDispatcher, vaultsManager: IVaultsManager ) : IUnlockManager { @@ -33,7 +35,7 @@ class UnlockManager( CoroutineScope(ioDispatcher).launch { vaultsManager.allStorages.collectLatest { mutex.lock() - val allKeys = repo.getAll() + val allKeys = keymapRepository.getAll() val allStorages = it.associateBy({ it.uuid }, { it }) val map = _openedStorages.value?.toMutableMap() ?: mutableMapOf() for(keymap in allKeys) { @@ -49,11 +51,12 @@ class UnlockManager( } } - private fun createEncryptedStorage(storage: IStorage, key: EncryptKey, uuid: UUID): EncryptedStorage { - return EncryptedStorage( - _source = storage, + private suspend fun createEncryptedStorage(storage: IStorage, key: EncryptKey, uuid: UUID): EncryptedStorage { + return EncryptedStorage.create( + source = storage, key = key, ioDispatcher = ioDispatcher, + metaInfoProvider = metaInfoRepository.createSingleStorageProvider(uuid), uuid = uuid ) } @@ -80,7 +83,7 @@ class UnlockManager( val encStorage = createEncryptedStorage(storage, keymap.key, keymap.destUuid) opened[storage.uuid] = encStorage _openedStorages.value = opened - repo.add(keymap) + keymapRepository.add(keymap) mutex.unlock() } @@ -97,7 +100,7 @@ class UnlockManager( remove(storage.uuid) } enc.dispose() - repo.delete(model) + keymapRepository.delete(model) mutex.unlock() } } \ No newline at end of file diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/storages/encrypt/EncryptedStorage.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/storages/encrypt/EncryptedStorage.kt new file mode 100644 index 0000000..d8e9bab --- /dev/null +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/storages/encrypt/EncryptedStorage.kt @@ -0,0 +1,96 @@ +package com.github.nullptroma.wallenc.data.storages.encrypt + +import com.github.nullptroma.wallenc.data.db.app.repository.StorageMetaInfoRepository +import com.github.nullptroma.wallenc.domain.common.impl.CommonStorageMetaInfo +import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey +import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo +import com.github.nullptroma.wallenc.domain.interfaces.IStorage +import com.github.nullptroma.wallenc.domain.interfaces.IStorageMetaInfo +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.DisposableHandle +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.withContext +import java.util.UUID + +class EncryptedStorage private constructor( + private val source: IStorage, + key: EncryptKey, + private val ioDispatcher: CoroutineDispatcher, + private val metaInfoProvider: StorageMetaInfoRepository.SingleStorageMetaInfoProvider, + override val uuid: UUID = UUID.randomUUID() +) : IStorage, DisposableHandle { + override val size: StateFlow + get() = source.size + override val numberOfFiles: StateFlow + get() = source.numberOfFiles + + private val _metaInfo = MutableStateFlow( + CommonStorageMetaInfo() + ) + override val metaInfo: StateFlow + get() = _metaInfo + override val isVirtualStorage: Boolean = true + + override val isAvailable: StateFlow + get() = source.isAvailable + override val accessor: EncryptedStorageAccessor = + EncryptedStorageAccessor(source.accessor, key, ioDispatcher) + + private suspend fun init() { + readMeta() + } + + private suspend fun readMeta() = withContext(ioDispatcher) { + var meta = metaInfoProvider.get() + if(meta == null) { + meta = CommonStorageMetaInfo() + metaInfoProvider.set(meta) + } + _metaInfo.value = meta + } + + override suspend fun rename(newName: String) = withContext(ioDispatcher) { + val cur = _metaInfo.value + val newMeta = CommonStorageMetaInfo( + encInfo = cur.encInfo, + name = newName + ) + _metaInfo.value = newMeta + metaInfoProvider.set(newMeta) + } + + override suspend fun setEncInfo(encInfo: StorageEncryptionInfo) = withContext(ioDispatcher) { + val cur = _metaInfo.value + val newMeta = CommonStorageMetaInfo( + encInfo = encInfo, + name = cur.name + ) + _metaInfo.value = newMeta + metaInfoProvider.set(newMeta) + } + + override fun dispose() { + accessor.dispose() + } + + companion object { + suspend fun create( + source: IStorage, + key: EncryptKey, + ioDispatcher: CoroutineDispatcher, + metaInfoProvider: StorageMetaInfoRepository.SingleStorageMetaInfoProvider, + uuid: UUID = UUID.randomUUID() + ): EncryptedStorage = withContext(ioDispatcher) { + val storage = EncryptedStorage( + source = source, + key = key, + ioDispatcher = ioDispatcher, + metaInfoProvider = metaInfoProvider, + uuid = uuid + ) + storage.init() + return@withContext storage + } + } +} \ No newline at end of file diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/EncryptedStorageAccessor.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/storages/encrypt/EncryptedStorageAccessor.kt similarity index 98% rename from domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/EncryptedStorageAccessor.kt rename to data/src/main/java/com/github/nullptroma/wallenc/data/storages/encrypt/EncryptedStorageAccessor.kt index e082258..724f660 100644 --- a/domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/EncryptedStorageAccessor.kt +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/storages/encrypt/EncryptedStorageAccessor.kt @@ -1,10 +1,11 @@ -package com.github.nullptroma.wallenc.domain.encrypt +package com.github.nullptroma.wallenc.data.storages.encrypt import com.github.nullptroma.wallenc.domain.common.impl.CommonDirectory import com.github.nullptroma.wallenc.domain.common.impl.CommonFile import com.github.nullptroma.wallenc.domain.common.impl.CommonMetaInfo import com.github.nullptroma.wallenc.domain.datatypes.DataPackage import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey +import com.github.nullptroma.wallenc.domain.encrypt.Encryptor import com.github.nullptroma.wallenc.domain.interfaces.IDirectory import com.github.nullptroma.wallenc.domain.interfaces.IFile import com.github.nullptroma.wallenc.domain.interfaces.IMetaInfo diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/local/LocalStorage.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/storages/local/LocalStorage.kt similarity index 55% rename from data/src/main/java/com/github/nullptroma/wallenc/data/vaults/local/LocalStorage.kt rename to data/src/main/java/com/github/nullptroma/wallenc/data/storages/local/LocalStorage.kt index c0312fe..0658ec1 100644 --- a/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/local/LocalStorage.kt +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/storages/local/LocalStorage.kt @@ -1,4 +1,4 @@ -package com.github.nullptroma.wallenc.data.vaults.local +package com.github.nullptroma.wallenc.data.storages.local import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.github.nullptroma.wallenc.domain.common.impl.CommonStorageMetaInfo @@ -24,14 +24,8 @@ class LocalStorage( override val numberOfFiles: StateFlow get() = accessor.numberOfFiles - private val _metaInfo = MutableStateFlow( - CommonStorageMetaInfo( - encInfo = StorageEncryptionInfo( - isEncrypted = false, - encryptedTestData = null - ), - name = null - ) + private val _metaInfo = MutableStateFlow( + CommonStorageMetaInfo() ) override val metaInfo: StateFlow get() = _metaInfo @@ -40,49 +34,60 @@ class LocalStorage( get() = accessor.isAvailable private val _accessor = LocalStorageAccessor(absolutePath, ioDispatcher) override val accessor: IStorageAccessor = _accessor - - private val encInfoFileName: String = "$uuid$ENC_INFO_FILE_POSTFIX" + override val isVirtualStorage: Boolean = false + private val metaInfoFileName: String = "$uuid$ENC_INFO_FILE_POSTFIX" suspend fun init() { _accessor.init() - readEncInfo() + readMetaInfo() } - private suspend fun readEncInfo() = withContext(ioDispatcher) { - var enc: StorageEncryptionInfo? = null + private suspend fun readMetaInfo() = withContext(ioDispatcher) { + var meta: CommonStorageMetaInfo var reader: InputStream? = null try { - reader = _accessor.openReadSystemFile(encInfoFileName) - enc = jackson.readValue(reader, StorageEncryptionInfo::class.java) + reader = _accessor.openReadSystemFile(metaInfoFileName) + meta = jackson.readValue(reader, CommonStorageMetaInfo::class.java) } catch(e: Exception) { // чтение не удалось, значит нужно записать файл - enc = StorageEncryptionInfo( - isEncrypted = false, - encryptedTestData = null - ) - setEncInfo(enc) + meta = CommonStorageMetaInfo() + updateMetaInfo(meta) } finally { reader?.close() } - _metaInfo.value = _metaInfo.value.copy(encInfo = enc) + _metaInfo.value = meta } - suspend fun setEncInfo(enc: StorageEncryptionInfo) = withContext(ioDispatcher) { - val writer = _accessor.openWriteSystemFile(encInfoFileName) + private suspend fun updateMetaInfo(meta: IStorageMetaInfo) = withContext(ioDispatcher) { + val writer = _accessor.openWriteSystemFile(metaInfoFileName) try { - jackson.writeValue(writer, enc) + jackson.writeValue(writer, meta) } catch (e: Exception) { - TODO("Это никогда не должно произойти") + throw e } - writer.close() - _metaInfo.value = _metaInfo.value.copy(encInfo = enc) + finally { + writer.close() + } + _metaInfo.value = meta } - override suspend fun rename(newName: String) { - TODO("Not yet implemented") + override suspend fun rename(newName: String) = withContext(ioDispatcher) { + val curMeta = metaInfo.value + updateMetaInfo(CommonStorageMetaInfo( + encInfo = curMeta.encInfo, + name = newName + )) + } + + override suspend fun setEncInfo(encInfo: StorageEncryptionInfo) = withContext(ioDispatcher) { + val curMeta = metaInfo.value + updateMetaInfo(CommonStorageMetaInfo( + encInfo = encInfo, + name = curMeta.name + )) } companion object { diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/local/LocalStorageAccessor.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/storages/local/LocalStorageAccessor.kt similarity index 98% rename from data/src/main/java/com/github/nullptroma/wallenc/data/vaults/local/LocalStorageAccessor.kt rename to data/src/main/java/com/github/nullptroma/wallenc/data/storages/local/LocalStorageAccessor.kt index ef2a5d6..28ecc75 100644 --- a/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/local/LocalStorageAccessor.kt +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/storages/local/LocalStorageAccessor.kt @@ -1,4 +1,4 @@ -package com.github.nullptroma.wallenc.data.vaults.local +package com.github.nullptroma.wallenc.data.storages.local import com.fasterxml.jackson.core.JacksonException import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper @@ -57,7 +57,7 @@ class LocalStorageAccessor( private val _dirsUpdates = MutableSharedFlow>() override val dirsUpdates: SharedFlow> = _dirsUpdates - suspend fun init() { + suspend fun init() = withContext(ioDispatcher) { // запускам сканирование хранилища scanSizeAndNumOfFiles() } @@ -251,11 +251,11 @@ class LocalStorageAccessor( * Считает файлы и их размер. Не бросает исключения, если файлы недоступны * @throws none Если возникла ошибка, оставляет размер и количества файлов равными null */ - private suspend fun scanSizeAndNumOfFiles() { + private suspend fun scanSizeAndNumOfFiles() = withContext(ioDispatcher) { if (!checkAvailable()) { _size.value = null _numberOfFiles.value = null - return + return@withContext } var size = 0L @@ -280,8 +280,8 @@ class LocalStorageAccessor( return@withContext listOf() val list = mutableListOf() - scanStorage(baseStoragePath = "/", maxDepth = -1, fileCallback = { _, CommonFile -> - list.add(CommonFile) + scanStorage(baseStoragePath = "/", maxDepth = -1, fileCallback = { _, commonFile -> + list.add(commonFile) }) return@withContext list } diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/local/LocalVault.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/LocalVault.kt similarity index 96% rename from data/src/main/java/com/github/nullptroma/wallenc/data/vaults/local/LocalVault.kt rename to data/src/main/java/com/github/nullptroma/wallenc/data/vaults/LocalVault.kt index d9a1f31..6d3e8a5 100644 --- a/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/local/LocalVault.kt +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/LocalVault.kt @@ -1,6 +1,7 @@ -package com.github.nullptroma.wallenc.data.vaults.local +package com.github.nullptroma.wallenc.data.vaults import android.content.Context +import com.github.nullptroma.wallenc.data.storages.local.LocalStorage import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo import com.github.nullptroma.wallenc.domain.enums.VaultType import com.github.nullptroma.wallenc.domain.interfaces.IStorage diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/VaultsManager.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/VaultsManager.kt index f863939..b0a9267 100644 --- a/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/VaultsManager.kt +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/VaultsManager.kt @@ -1,7 +1,6 @@ package com.github.nullptroma.wallenc.data.vaults import android.content.Context -import com.github.nullptroma.wallenc.data.vaults.local.LocalVault import com.github.nullptroma.wallenc.domain.interfaces.IStorage import com.github.nullptroma.wallenc.domain.interfaces.IVault import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/common/impl/CommonStorageMetaInfo.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/common/impl/CommonStorageMetaInfo.kt index 9fc2f77..f99270d 100644 --- a/domain/src/main/java/com/github/nullptroma/wallenc/domain/common/impl/CommonStorageMetaInfo.kt +++ b/domain/src/main/java/com/github/nullptroma/wallenc/domain/common/impl/CommonStorageMetaInfo.kt @@ -9,7 +9,10 @@ import java.time.Instant data class CommonStorageMetaInfo( - override val encInfo: StorageEncryptionInfo?, - override val name: String?, + override val encInfo: StorageEncryptionInfo = StorageEncryptionInfo( + isEncrypted = false, + encryptedTestData = null + ), + override val name: String? = null, override val lastModified: Instant = Clock.systemUTC().instant() ) : IStorageMetaInfo \ No newline at end of file diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/EncryptedStorage.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/EncryptedStorage.kt deleted file mode 100644 index bb81434..0000000 --- a/domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/EncryptedStorage.kt +++ /dev/null @@ -1,52 +0,0 @@ -package com.github.nullptroma.wallenc.domain.encrypt - -import com.github.nullptroma.wallenc.domain.common.impl.CommonStorageMetaInfo -import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey -import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo -import com.github.nullptroma.wallenc.domain.interfaces.IStorage -import com.github.nullptroma.wallenc.domain.interfaces.IStorageMetaInfo -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.DisposableHandle -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.stateIn -import java.util.UUID - -class EncryptedStorage( - private val _source: IStorage, - key: EncryptKey, - private val ioDispatcher: CoroutineDispatcher, - override val uuid: UUID = UUID.randomUUID() -) : IStorage, DisposableHandle { - override val size: StateFlow - get() = _source.size - override val numberOfFiles: StateFlow - get() = _source.numberOfFiles - - private val _metaInfo = MutableStateFlow( - CommonStorageMetaInfo( - encInfo = StorageEncryptionInfo( - isEncrypted = false, - encryptedTestData = null - ), - name = null - ) - ) - override val metaInfo: StateFlow - get() = _metaInfo - - override val isAvailable: StateFlow - get() = _source.isAvailable - override val accessor: EncryptedStorageAccessor = - EncryptedStorageAccessor(_source.accessor, key, ioDispatcher) - - override suspend fun rename(newName: String) { - TODO("Not yet implemented") - } - - override fun dispose() { - accessor.dispose() - } -} \ No newline at end of file diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorage.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorage.kt index 2ad9500..3fb0630 100644 --- a/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorage.kt +++ b/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorage.kt @@ -1,7 +1,10 @@ package com.github.nullptroma.wallenc.domain.interfaces +import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo + interface IStorage: IStorageInfo { val accessor: IStorageAccessor suspend fun rename(newName: String) + suspend fun setEncInfo(encInfo: StorageEncryptionInfo) } diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageInfo.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageInfo.kt index cca8176..dec9aad 100644 --- a/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageInfo.kt +++ b/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageInfo.kt @@ -9,4 +9,5 @@ sealed interface IStorageInfo { val size: StateFlow val numberOfFiles: StateFlow val metaInfo: StateFlow + val isVirtualStorage: Boolean } \ No newline at end of file diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageMetaInfo.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageMetaInfo.kt index c17f25d..27766ab 100644 --- a/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageMetaInfo.kt +++ b/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageMetaInfo.kt @@ -1,12 +1,10 @@ package com.github.nullptroma.wallenc.domain.interfaces import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo -import kotlinx.coroutines.flow.StateFlow -import java.time.Clock import java.time.Instant interface IStorageMetaInfo { - val encInfo: StorageEncryptionInfo? + val encInfo: StorageEncryptionInfo val name: String? val lastModified: Instant diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6856d03..8e92930 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] agp = "8.8.0" jacksonModuleKotlin = "2.18.2" -kotlin = "2.0.10" +kotlin = "2.0.20" coreKtx = "1.15.0" junit = "4.13.2" junitVersion = "1.2.1" @@ -17,12 +17,11 @@ hiltNavigation = "1.2.0" timber = "5.0.1" yandexAuthSdk = "3.1.2" daggerHilt = "2.52" -ksp = "2.0.10-1.0.24" +ksp = "2.0.20-1.0.25" room = "2.6.1" retrofit = "2.11.0" appcompat = "1.7.0" material = "1.12.0" -runtimeAndroid = "1.7.5" [libraries] jackson-datatype-jsr310 = { module = "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" } diff --git a/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/screens/local/vault/LocalVaultScreen.kt b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/screens/local/vault/LocalVaultScreen.kt index 6c4a8c6..de56480 100644 --- a/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/screens/local/vault/LocalVaultScreen.kt +++ b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/screens/local/vault/LocalVaultScreen.kt @@ -44,14 +44,14 @@ fun LocalVaultScreen(modifier: Modifier = Modifier, detectTapGestures( onTap = { _ -> viewModel.printStorageInfoToLog(it) } ) - }) { + }.padding(8.dp)) { val available by it.isAvailable.collectAsStateWithLifecycle() val numOfFiles by it.numberOfFiles.collectAsStateWithLifecycle() val size by it.size.collectAsStateWithLifecycle() val metaInfo by it.metaInfo.collectAsStateWithLifecycle() val enc = metaInfo.encInfo - Column { + Column(modifier = Modifier.padding(4.dp)) { Text(it.uuid.toString()) Text("IsAvailable: $available") Text("Files: $numOfFiles")