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 41d5517..3fdb62d 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 @@ -13,9 +13,9 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext import java.util.UUID @@ -24,43 +24,41 @@ class UnlockManager( private val ioDispatcher: CoroutineDispatcher, vaultsManager: IVaultsManager ) : IUnlockManager { - private val _openedStorages = MutableStateFlow?>(null) - override val openedStorages: StateFlow?> + private val _openedStorages = MutableStateFlow>(emptyMap()) + override val openedStorages: StateFlow> get() = _openedStorages private val mutex = Mutex() 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) + mutex.withLock { + val allKeys = keymapRepository.getAll() + val keysToRemove = mutableListOf() + val allStorages = it.toMutableList() + val map = _openedStorages.value.toMutableMap() + while(allStorages.isNotEmpty()) { + 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 + 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() } - keymapRepository.delete(*keysToRemove.toTypedArray()) // удалить мёртвые ключи - _openedStorages.value = map.toMap() - mutex.unlock() } } } @@ -78,27 +76,27 @@ class UnlockManager( 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") + return@withContext mutex.withLock { + 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 opened = _openedStorages.value.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 + 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) + encStorage + } } /** @@ -106,30 +104,37 @@ class UnlockManager( * @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) + mutex.withLock { + val opened = _openedStorages.value.toMutableMap() + closeBySourceUuid(opened, uuid) + _openedStorages.value = opened } - enc.dispose() - keymapRepository.delete(model) - mutex.unlock() } // Закрытие отображения по экземпляру (source или decrypted). override suspend fun close(storage: IStorage) { - val opened = _openedStorages.first { it != null }!! + val opened = _openedStorages.value val source = opened.entries.firstOrNull { it.key == storage.uuid || it.value.uuid == storage.uuid } if (source != null) close(source.key) } + + private suspend fun closeBySourceUuid(opened: MutableMap, sourceUuid: UUID) { + val enc = opened[sourceUuid] ?: return + val childSourceUuid = opened.entries.firstOrNull { it.value.uuid == enc.uuid }?.key + if (childSourceUuid != null) { + closeBySourceUuid(opened, childSourceUuid) + } + opened.remove(sourceUuid) + enc.dispose() + keymapRepository.delete( + StorageKeyMap( + sourceUuid = sourceUuid, + destUuid = enc.uuid, + key = EncryptKey("") + ) + ) + } } \ No newline at end of file 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 118315d..b953ab7 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 @@ -12,7 +12,7 @@ interface IUnlockManager { /** * Хранилища, для которых есть ключ шифрования */ - val openedStorages: StateFlow?> + val openedStorages: StateFlow> suspend fun open(storage: IStorage, key: EncryptKey): IStorage suspend fun close(storage: IStorage) diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/usecases/GetOpenedStoragesUseCase.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/usecases/GetOpenedStoragesUseCase.kt index 0789823..661ca28 100644 --- a/domain/src/main/java/com/github/nullptroma/wallenc/domain/usecases/GetOpenedStoragesUseCase.kt +++ b/domain/src/main/java/com/github/nullptroma/wallenc/domain/usecases/GetOpenedStoragesUseCase.kt @@ -7,6 +7,6 @@ import kotlinx.coroutines.flow.map import java.util.UUID class GetOpenedStoragesUseCase(private val unlockManager: IUnlockManager) { - val openedStorages: StateFlow?> + val openedStorages: StateFlow> get() = unlockManager.openedStorages } \ No newline at end of file diff --git a/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/screens/local/vault/LocalVaultViewModel.kt b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/screens/local/vault/LocalVaultViewModel.kt index 4019cd9..0ec2fc6 100644 --- a/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/screens/local/vault/LocalVaultViewModel.kt +++ b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/screens/local/vault/LocalVaultViewModel.kt @@ -59,7 +59,7 @@ class LocalVaultViewModel @Inject constructor( private fun collectFlows() { viewModelScope.launch { manageLocalVaultUseCase.localStorages.combine(getOpenedStoragesUseCase.openedStorages) { local, opened -> - if(local == null || opened == null) + if(local == null) return@combine null val list = mutableListOf>() for (storage in local) {