IUnlockManager теперь IVault

This commit is contained in:
Пытков Роман
2025-02-11 17:55:54 +03:00
parent e1646611c2
commit 85b8517a76
8 changed files with 115 additions and 28 deletions

View File

@@ -25,9 +25,17 @@ class SingletonModule {
@Singleton @Singleton
fun provideVaultsManager( fun provideVaultsManager(
@IoDispatcher ioDispatcher: CoroutineDispatcher, @IoDispatcher ioDispatcher: CoroutineDispatcher,
@ApplicationContext context: Context @ApplicationContext context: Context,
keyRepo: StorageKeyMapRepository,
): IVaultsManager { ): IVaultsManager {
return VaultsManager(ioDispatcher, context) return VaultsManager(ioDispatcher, context, keyRepo)
}
@Provides
fun provideUnlockManager(
vaultsManager: IVaultsManager
): IUnlockManager {
return vaultsManager.unlockManager
} }
@Provides @Provides
@@ -47,18 +55,4 @@ class SingletonModule {
): StorageMetaInfoRepository { ): StorageMetaInfoRepository {
return StorageMetaInfoRepository(dao, ioDispatcher) return StorageMetaInfoRepository(dao, ioDispatcher)
} }
@Provides
@Singleton
fun provideUnlockManager(
@IoDispatcher ioDispatcher: CoroutineDispatcher,
keyRepo: StorageKeyMapRepository,
vaultsManager: IVaultsManager
): IUnlockManager {
return UnlockManager(
keymapRepository = keyRepo,
ioDispatcher = ioDispatcher,
vaultsManager = vaultsManager
)
}
} }

View File

@@ -5,7 +5,9 @@ import com.github.nullptroma.wallenc.data.db.app.repository.StorageMetaInfoRepos
import com.github.nullptroma.wallenc.data.model.StorageKeyMap import com.github.nullptroma.wallenc.data.model.StorageKeyMap
import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
import com.github.nullptroma.wallenc.data.storages.encrypt.EncryptedStorage 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.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.IStorage
import com.github.nullptroma.wallenc.domain.interfaces.IUnlockManager import com.github.nullptroma.wallenc.domain.interfaces.IUnlockManager
import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager
@@ -16,6 +18,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@@ -30,6 +33,19 @@ class UnlockManager(
override val openedStorages: StateFlow<Map<UUID, IStorage>?> override val openedStorages: StateFlow<Map<UUID, IStorage>?>
get() = _openedStorages get() = _openedStorages
private val mutex = Mutex() private val mutex = Mutex()
override val type: VaultType
get() = VaultType.DECRYPTED
override val uuid: UUID
get() = TODO("Not yet implemented")
override val isAvailable: StateFlow<Boolean>
get() = MutableStateFlow(true)
override val totalSpace: StateFlow<Int?>
get() = MutableStateFlow(null)
override val availableSpace: StateFlow<Int?>
get() = MutableStateFlow(null)
override val storages: StateFlow<List<IStorage>?>
get() = TODO()
init { init {
CoroutineScope(ioDispatcher).launch { CoroutineScope(ioDispatcher).launch {
@@ -103,20 +119,54 @@ class UnlockManager(
return@withContext encStorage return@withContext encStorage
} }
override suspend fun close(storage: IStorage) = withContext(ioDispatcher) { /**
* Закрыть шифрование хранилища, закрывает рекурсивно, удаляя все ключи
* @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() mutex.lock()
val opened = _openedStorages.first { it != null }!! val opened = _openedStorages.first { it != null }!!
val enc = opened[storage.uuid] ?: return@withContext val enc = opened[uuid] ?: return@withContext
close(enc)
val model = StorageKeyMap( val model = StorageKeyMap(
sourceUuid = storage.uuid, sourceUuid = uuid,
destUuid = enc.uuid, destUuid = enc.uuid,
key = EncryptKey("") key = EncryptKey("")
) )
_openedStorages.value = opened.toMutableMap().apply { _openedStorages.value = opened.toMutableMap().apply {
remove(storage.uuid) remove(uuid)
} }
enc.dispose() enc.dispose()
keymapRepository.delete(model) keymapRepository.delete(model)
mutex.unlock() 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)
}
} }

View File

@@ -1,19 +1,30 @@
package com.github.nullptroma.wallenc.data.vaults package com.github.nullptroma.wallenc.data.vaults
import android.content.Context import android.content.Context
import com.github.nullptroma.wallenc.data.db.app.repository.StorageKeyMapRepository
import com.github.nullptroma.wallenc.data.storages.UnlockManager
import com.github.nullptroma.wallenc.domain.interfaces.IStorage import com.github.nullptroma.wallenc.domain.interfaces.IStorage
import com.github.nullptroma.wallenc.domain.interfaces.IUnlockManager
import com.github.nullptroma.wallenc.domain.interfaces.IVault import com.github.nullptroma.wallenc.domain.interfaces.IVault
import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
class VaultsManager(ioDispatcher: CoroutineDispatcher, context: Context) : IVaultsManager { class VaultsManager(ioDispatcher: CoroutineDispatcher, context: Context, keyRepo: StorageKeyMapRepository) : IVaultsManager {
override val localVault = LocalVault(ioDispatcher, context) override val localVault = LocalVault(ioDispatcher, context)
override val unlockManager: IUnlockManager = UnlockManager(
keymapRepository = keyRepo,
ioDispatcher = ioDispatcher,
vaultsManager = this
)
override val remoteVaults: StateFlow<List<IVault>> override val remoteVaults: StateFlow<List<IVault>>
get() = TODO("Not yet implemented") get() = TODO("Not yet implemented")
override val allStorages: StateFlow<List<IStorage>> override val allStorages: StateFlow<List<IStorage>>
get() = localVault.storages get() = localVault.storages
override val allVaults: StateFlow<List<IVault>>
get() = MutableStateFlow(listOf(localVault, unlockManager))
override fun addYandexVault(email: String, token: String) { override fun addYandexVault(email: String, token: String) {
TODO("Not yet implemented") TODO("Not yet implemented")

View File

@@ -2,5 +2,6 @@ package com.github.nullptroma.wallenc.domain.enums
enum class VaultType { enum class VaultType {
LOCAL, LOCAL,
DECRYPTED,
YANDEX YANDEX
} }

View File

@@ -4,7 +4,7 @@ import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import java.util.UUID import java.util.UUID
interface IUnlockManager { interface IUnlockManager: IVault {
/** /**
* Хранилища, для которых есть ключ шифрования * Хранилища, для которых есть ключ шифрования
*/ */
@@ -12,4 +12,5 @@ interface IUnlockManager {
suspend fun open(storage: IStorage, key: EncryptKey): IStorage suspend fun open(storage: IStorage, key: EncryptKey): IStorage
suspend fun close(storage: IStorage) suspend fun close(storage: IStorage)
suspend fun close(uuid: UUID): Unit
} }

View File

@@ -4,8 +4,9 @@ import kotlinx.coroutines.flow.StateFlow
interface IVaultsManager { interface IVaultsManager {
val localVault: IVault val localVault: IVault
val unlockManager: IUnlockManager
val remoteVaults: StateFlow<List<IVault>> val remoteVaults: StateFlow<List<IVault>>
val allStorages: StateFlow<List<IStorage>> val allStorages: StateFlow<List<IStorage>>
val allVaults: StateFlow<List<IVault>>
fun addYandexVault(email: String, token: String) fun addYandexVault(email: String, token: String)
} }

View File

@@ -0,0 +1,12 @@
package com.github.nullptroma.wallenc.domain.usecases
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
import com.github.nullptroma.wallenc.domain.interfaces.IStorageInfo
class RemoveStorageUseCase {
suspend fun rename(storage: IStorageInfo, newName: String) {
when (storage) {
is IStorage -> storage.rename(newName)
}
}
}

View File

@@ -38,7 +38,9 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.PlatformTextStyle import androidx.compose.ui.text.PlatformTextStyle
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
@@ -65,12 +67,16 @@ fun StorageTree(
val numOfFiles by cur.numberOfFiles.collectAsStateWithLifecycle() val numOfFiles by cur.numberOfFiles.collectAsStateWithLifecycle()
val size by cur.size.collectAsStateWithLifecycle() val size by cur.size.collectAsStateWithLifecycle()
val metaInfo by cur.metaInfo.collectAsStateWithLifecycle() val metaInfo by cur.metaInfo.collectAsStateWithLifecycle()
//val isAvailable by cur.isAvailable.collectAsStateWithLifecycle()
val isAvailable = metaInfo.name?.startsWith("1") != true
val borderColor = val borderColor =
if (cur.isVirtualStorage) MaterialTheme.colorScheme.secondary else MaterialTheme.colorScheme.primary if (cur.isVirtualStorage) MaterialTheme.colorScheme.secondary else MaterialTheme.colorScheme.primary
Column(modifier) { Column(modifier) {
Box(modifier = Modifier Box(
modifier = Modifier
.height(IntrinsicSize.Min) .height(IntrinsicSize.Min)
.zIndex(100f)) { .zIndex(100f)
) {
val interactionSource = remember { MutableInteractionSource() } val interactionSource = remember { MutableInteractionSource() }
Box( Box(
modifier = Modifier modifier = Modifier
@@ -115,7 +121,7 @@ fun StorageTree(
modifier = Modifier, modifier = Modifier,
horizontalAlignment = Alignment.End horizontalAlignment = Alignment.End
) { ) {
Box(modifier = Modifier.padding(0.dp, 8.dp, 8.dp, 0.dp)) { Box(modifier = Modifier.padding(0.dp, 0.dp, 0.dp, 0.dp)) {
var expanded by remember { mutableStateOf(false) } var expanded by remember { mutableStateOf(false) }
var showRenameDialog by remember { mutableStateOf(false) } var showRenameDialog by remember { mutableStateOf(false) }
var showRemoveConfirmationDiaglog by remember { mutableStateOf(false) } var showRemoveConfirmationDiaglog by remember { mutableStateOf(false) }
@@ -195,6 +201,17 @@ fun StorageTree(
} }
} }
} }
if(!isAvailable) {
Box(
modifier = Modifier
.clip(
CardDefaults.shape
)
.fillMaxSize()
.alpha(0.5f)
.background(Color.Black)
)
}
} }
for (i in tree.children ?: listOf()) { for (i in tree.children ?: listOf()) {
StorageTree( StorageTree(