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 4289b10..5185b40 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 @@ -24,8 +24,8 @@ class UseCasesModule { @Provides @Singleton - fun provideManageLocalVaultUseCase(vaultsManager: IVaultsManager, unlockManager: IUnlockManager): ManageLocalVaultUseCase { - return ManageLocalVaultUseCase(vaultsManager, unlockManager) + fun provideManageLocalVaultUseCase(vaultsManager: IVaultsManager): ManageLocalVaultUseCase { + return ManageLocalVaultUseCase(vaultsManager) } @Provides diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/storages/UnlockManager.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/storages/UnlockManager.kt index 55bcab8..41d5517 100644 --- a/data/src/main/java/com/github/nullptroma/wallenc/data/storages/UnlockManager.kt +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/storages/UnlockManager.kt @@ -1,26 +1,19 @@ 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.data.storages.encrypt.EncryptedStorage -import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo import com.github.nullptroma.wallenc.domain.encrypt.Encryptor -import com.github.nullptroma.wallenc.domain.enums.VaultType import com.github.nullptroma.wallenc.domain.interfaces.IStorage import com.github.nullptroma.wallenc.domain.interfaces.IUnlockManager import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.withContext @@ -35,23 +28,6 @@ class UnlockManager( override val openedStorages: StateFlow?> get() = _openedStorages private val mutex = Mutex() - override val type: VaultType - get() = VaultType.DECRYPTED - override val uuid: UUID - get() = TODO("Not yet implemented") - override val isAvailable: StateFlow - get() = MutableStateFlow(true) - override val totalSpace: StateFlow - get() = MutableStateFlow(null) - override val availableSpace: StateFlow - get() = MutableStateFlow(null) - - override val storages: StateFlow?> - get() = openedStorages.map { it?.values?.toList() }.stateIn( - scope = CoroutineScope(ioDispatcher), - started = SharingStarted.WhileSubscribed(5000L), - initialValue = null - ) init { CoroutineScope(ioDispatcher).launch { @@ -125,14 +101,6 @@ class UnlockManager( return@withContext encStorage } - /** - * Закрыть шифрование хранилища, закрывает рекурсивно, удаляя все ключи - * @param storage исходное хранилище, а не расшифрованное отображение - */ - override suspend fun close(storage: IStorage) { - close(storage.uuid) - } - /** * Закрыть шифрование хранилища, закрывает рекурсивно, удаляя все ключи * @param uuid uuid исходного хранилища @@ -155,24 +123,13 @@ class UnlockManager( mutex.unlock() } - override suspend fun createStorage(): IStorage { - throw UnsupportedOperationException("Нельзя создать кошелёк на UnlockManager") // TODO - } - - override suspend fun createStorage(enc: StorageEncryptionInfo): IStorage { - throw UnsupportedOperationException("Нельзя создать кошелёк на UnlockManager") // TODO - } - - /** - * Закрыть отображение - * @param storage исходное или расшифрованное хранилище - */ - override suspend fun remove(storage: IStorage) { + // Закрытие отображения по экземпляру (source или decrypted). + override suspend fun close(storage: IStorage) { val opened = _openedStorages.first { it != null }!! val source = opened.entries.firstOrNull { it.key == storage.uuid || it.value.uuid == storage.uuid } - if(source != null) + if (source != null) close(source.key) } } \ 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/vaults/UnlockManager.kt deleted file mode 100644 index b3d709c..0000000 --- a/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/UnlockManager.kt +++ /dev/null @@ -1,176 +0,0 @@ -package com.github.nullptroma.wallenc.data.vaults - -import com.github.nullptroma.wallenc.data.db.app.repository.StorageKeyMapRepository -import com.github.nullptroma.wallenc.data.model.StorageKeyMap -import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey -import com.github.nullptroma.wallenc.data.storages.encrypt.EncryptedStorage -import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo -import com.github.nullptroma.wallenc.domain.encrypt.Encryptor -import com.github.nullptroma.wallenc.domain.enums.VaultType -import com.github.nullptroma.wallenc.domain.interfaces.IStorage -import com.github.nullptroma.wallenc.domain.interfaces.IUnlockManager -import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.launch -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.withContext -import java.util.UUID - -class UnlockManager( - private val keymapRepository: StorageKeyMapRepository, - private val ioDispatcher: CoroutineDispatcher, - vaultsManager: IVaultsManager -) : IUnlockManager { - private val _openedStorages = MutableStateFlow?>(null) - override val openedStorages: StateFlow?> - get() = _openedStorages - private val mutex = Mutex() - override val type: VaultType - get() = VaultType.DECRYPTED - override val uuid: UUID - get() = TODO("Not yet implemented") - override val isAvailable: StateFlow - get() = MutableStateFlow(true) - override val totalSpace: StateFlow - get() = MutableStateFlow(null) - override val availableSpace: StateFlow - get() = MutableStateFlow(null) - - override val storages: StateFlow?> - get() = openedStorages.map { it?.values?.toList() }.stateIn( - scope = CoroutineScope(ioDispatcher), - started = SharingStarted.WhileSubscribed(5000L), - initialValue = null - ) - - init { - CoroutineScope(ioDispatcher).launch { - vaultsManager.allStorages.collectLatest { - mutex.lock() - val allKeys = keymapRepository.getAll() - val usedKeys = mutableListOf() - val keysToRemove = mutableListOf() - val allStorages = it.toMutableList() - val map = _openedStorages.value?.toMutableMap() ?: mutableMapOf() - while(allStorages.size > 0) { - val storage = allStorages[allStorages.size-1] - val key = allKeys.find { key -> key.sourceUuid == storage.uuid } - if(key == null) { - allStorages.removeAt(allStorages.size - 1) - continue - } - try { - val encStorage = createEncryptedStorage(storage, key.key, key.destUuid) - map[storage.uuid] = encStorage - usedKeys.add(key) - allStorages.removeAt(allStorages.size - 1) - allStorages.add(encStorage) - } - catch (_: Exception) { - // ключ не подошёл - keysToRemove.add(key) - allStorages.removeAt(allStorages.size - 1) - } - } - keymapRepository.delete(*keysToRemove.toTypedArray()) // удалить мёртвые ключи - _openedStorages.value = map.toMap() - mutex.unlock() - } - } - } - - private suspend fun createEncryptedStorage(storage: IStorage, key: EncryptKey, uuid: UUID): EncryptedStorage { - return EncryptedStorage.create( - source = storage, - key = key, - ioDispatcher = ioDispatcher, - uuid = uuid - ) - } - - override suspend fun open( - storage: IStorage, - key: EncryptKey - ): EncryptedStorage = withContext(ioDispatcher) { - mutex.lock() - val encInfo = storage.metaInfo.value.encInfo ?: throw Exception("EncInfo is null") // TODO - if (!Encryptor.checkKey(key, encInfo)) - throw Exception("Incorrect Key") - - val opened = _openedStorages.first { it != null }!!.toMutableMap() - val cur = opened[storage.uuid] - if (cur != null) - throw Exception("Storage is already open") - - val keymap = StorageKeyMap( - sourceUuid = storage.uuid, - destUuid = UUID.randomUUID(), - key = key - ) - val encStorage = createEncryptedStorage(storage, keymap.key, keymap.destUuid) - opened[storage.uuid] = encStorage - _openedStorages.value = opened - keymapRepository.add(keymap) - mutex.unlock() - return@withContext encStorage - } - - /** - * Закрыть шифрование хранилища, закрывает рекурсивно, удаляя все ключи - * @param storage исходное хранилище, а не расшифрованное отображение - */ - override suspend fun close(storage: IStorage) { - close(storage.uuid) - } - - /** - * Закрыть шифрование хранилища, закрывает рекурсивно, удаляя все ключи - * @param uuid uuid исходного хранилища - */ - override suspend fun close(uuid: UUID): Unit = withContext(ioDispatcher) { - mutex.lock() - val opened = _openedStorages.first { it != null }!! - val enc = opened[uuid] ?: return@withContext - close(enc) - val model = StorageKeyMap( - sourceUuid = uuid, - destUuid = enc.uuid, - key = EncryptKey("") - ) - _openedStorages.value = opened.toMutableMap().apply { - remove(uuid) - } - enc.dispose() - keymapRepository.delete(model) - mutex.unlock() - } - - override suspend fun createStorage(): IStorage { - throw UnsupportedOperationException("Нельзя создать кошелёк на UnlockManager") // TODO - } - - override suspend fun createStorage(enc: StorageEncryptionInfo): IStorage { - throw UnsupportedOperationException("Нельзя создать кошелёк на UnlockManager") // TODO - } - - /** - * Закрыть отображение - * @param storage исходное или расшифрованное хранилище - */ - override suspend fun remove(storage: IStorage) { - val opened = _openedStorages.first { it != null }!! - val source = opened.entries.firstOrNull { - it.key == storage.uuid || it.value.uuid == storage.uuid - } - if(source != null) - close(source.key) - } -} \ No newline at end of file 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 bd43dd2..1d1308c 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 @@ -23,7 +23,7 @@ class VaultsManager(ioDispatcher: CoroutineDispatcher, context: Context, keyRepo override val allStorages: StateFlow> get() = localVault.storages override val allVaults: StateFlow> - get() = MutableStateFlow(listOf(localVault, unlockManager)) + get() = MutableStateFlow(listOf(localVault)) override fun addYandexVault(email: String, token: String) { diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IUnlockManager.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IUnlockManager.kt index ef44dbe..118315d 100644 --- a/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IUnlockManager.kt +++ b/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IUnlockManager.kt @@ -4,7 +4,11 @@ import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey import kotlinx.coroutines.flow.StateFlow import java.util.UUID -interface IUnlockManager: IVault { +/** + * Управляет виртуальными (расшифрованными) представлениями хранилищ. + * Не является vault-провайдером. + */ +interface IUnlockManager { /** * Хранилища, для которых есть ключ шифрования */ diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/usecases/ManageLocalVaultUseCase.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/usecases/ManageLocalVaultUseCase.kt index bd5b5b2..f98c250 100644 --- a/domain/src/main/java/com/github/nullptroma/wallenc/domain/usecases/ManageLocalVaultUseCase.kt +++ b/domain/src/main/java/com/github/nullptroma/wallenc/domain/usecases/ManageLocalVaultUseCase.kt @@ -1,15 +1,11 @@ package com.github.nullptroma.wallenc.domain.usecases -import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey -import com.github.nullptroma.wallenc.domain.encrypt.Encryptor import com.github.nullptroma.wallenc.domain.interfaces.IStorage import com.github.nullptroma.wallenc.domain.interfaces.IStorageInfo -import com.github.nullptroma.wallenc.domain.interfaces.IUnlockManager import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.map -class ManageLocalVaultUseCase(private val manager: IVaultsManager, private val unlockManager: IUnlockManager) { +class ManageLocalVaultUseCase(private val manager: IVaultsManager) { val localStorages: StateFlow?> get() = manager.localVault.storages