Добавлено StorageEncryptionInfo для локальных хранилищ
This commit is contained in:
@@ -2,7 +2,10 @@ package com.github.nullptroma.wallenc.app.di.modules.data
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.github.nullptroma.wallenc.app.di.modules.app.IoDispatcher
|
import com.github.nullptroma.wallenc.app.di.modules.app.IoDispatcher
|
||||||
|
import com.github.nullptroma.wallenc.data.db.app.dao.StorageKeyDao
|
||||||
|
import com.github.nullptroma.wallenc.data.vaults.UnlockManager
|
||||||
import com.github.nullptroma.wallenc.data.vaults.VaultsManager
|
import com.github.nullptroma.wallenc.data.vaults.VaultsManager
|
||||||
|
import com.github.nullptroma.wallenc.domain.interfaces.IUnlockManager
|
||||||
import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager
|
import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
@@ -21,4 +24,14 @@ class SingletonModule {
|
|||||||
@ApplicationContext context: Context): IVaultsManager {
|
@ApplicationContext context: Context): IVaultsManager {
|
||||||
return VaultsManager(ioDispatcher, context)
|
return VaultsManager(ioDispatcher, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideUnlockManager(@IoDispatcher ioDispatcher: CoroutineDispatcher,
|
||||||
|
dao: StorageKeyDao): IUnlockManager {
|
||||||
|
return UnlockManager(
|
||||||
|
dao = dao,
|
||||||
|
ioDispatcher = ioDispatcher
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,17 @@
|
|||||||
package com.github.nullptroma.wallenc.data.vaults
|
package com.github.nullptroma.wallenc.data.vaults
|
||||||
|
|
||||||
|
import com.github.nullptroma.wallenc.data.db.app.dao.StorageKeyDao
|
||||||
import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
|
import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
|
||||||
|
import com.github.nullptroma.wallenc.domain.encrypt.EncryptedStorage
|
||||||
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 kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
class UnlockManager: IUnlockManager {
|
class UnlockManager(dao: StorageKeyDao, ioDispatcher: CoroutineDispatcher): IUnlockManager {
|
||||||
private val _openedStorages = MutableStateFlow<Map<UUID, IStorage>>(mapOf())
|
private val _openedStorages = MutableStateFlow<Map<UUID, EncryptedStorage>>(mapOf())
|
||||||
override val openedStorages: StateFlow<Map<UUID, IStorage>>
|
override val openedStorages: StateFlow<Map<UUID, IStorage>>
|
||||||
get() = _openedStorages
|
get() = _openedStorages
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,89 @@
|
|||||||
package com.github.nullptroma.wallenc.data.vaults.local
|
package com.github.nullptroma.wallenc.data.vaults.local
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||||
|
import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo
|
||||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
|
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
|
||||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorageAccessor
|
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
|
|
||||||
class LocalStorage(
|
class LocalStorage(
|
||||||
override val uuid: UUID,
|
override val uuid: UUID,
|
||||||
override val isEncrypted: Boolean,
|
|
||||||
absolutePath: String,
|
absolutePath: String,
|
||||||
ioDispatcher: CoroutineDispatcher
|
ioDispatcher: CoroutineDispatcher,
|
||||||
) : IStorage {
|
) : IStorage {
|
||||||
override val size: StateFlow<Long?>
|
override val size: StateFlow<Long?>
|
||||||
get() = accessor.size
|
get() = accessor.size
|
||||||
override val numberOfFiles: StateFlow<Int?>
|
override val numberOfFiles: StateFlow<Int?>
|
||||||
get() = accessor.numberOfFiles
|
get() = accessor.numberOfFiles
|
||||||
override val name: StateFlow<String>
|
|
||||||
get() = TODO("Добавить класс в Domain, который с помощью accessor будет читать и сохранять имя в скрытую папку")
|
|
||||||
override val isAvailable: StateFlow<Boolean>
|
override val isAvailable: StateFlow<Boolean>
|
||||||
get() = accessor.isAvailable
|
get() = accessor.isAvailable
|
||||||
override val accessor: IStorageAccessor = LocalStorageAccessor(absolutePath, ioDispatcher)
|
override val accessor = LocalStorageAccessor(absolutePath, ioDispatcher)
|
||||||
|
|
||||||
|
private val _encInfo = MutableStateFlow<StorageEncryptionInfo?>(null)
|
||||||
|
override val encInfo: StateFlow<StorageEncryptionInfo?>
|
||||||
|
get() = _encInfo
|
||||||
|
override val name: StateFlow<String>
|
||||||
|
get() = TODO("Добавить класс в Domain, который с помощью accessor будет читать и сохранять имя в скрытую папку")
|
||||||
|
|
||||||
|
private val encInfoFileName: String = "$uuid$ENC_INFO_FILE_POSTFIX"
|
||||||
|
|
||||||
|
suspend fun init() {
|
||||||
|
accessor.init()
|
||||||
|
readEncInfo()
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun readEncInfo() {
|
||||||
|
accessor.touchFile(encInfoFileName)
|
||||||
|
accessor.setHidden(encInfoFileName, true)
|
||||||
|
val reader = accessor.openRead(encInfoFileName)
|
||||||
|
var enc: StorageEncryptionInfo? = null
|
||||||
|
try {
|
||||||
|
enc = _jackson.readValue(reader, StorageEncryptionInfo::class.java)
|
||||||
|
reader.close()
|
||||||
|
}
|
||||||
|
catch(e: Exception) {
|
||||||
|
reader.close()
|
||||||
|
// чтение не удалось, значит нужно записать файл
|
||||||
|
enc = StorageEncryptionInfo(
|
||||||
|
isEncrypted = false,
|
||||||
|
encryptedTestData = null
|
||||||
|
)
|
||||||
|
val writer = accessor.openWrite(encInfoFileName)
|
||||||
|
try {
|
||||||
|
_jackson.writeValue(writer, enc)
|
||||||
|
}
|
||||||
|
catch (e: Exception) {
|
||||||
|
TODO("Это никогда не должно произойти")
|
||||||
|
}
|
||||||
|
writer.close()
|
||||||
|
}
|
||||||
|
_encInfo.value = enc
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun setEncInfo(enc: StorageEncryptionInfo) {
|
||||||
|
accessor.touchFile(encInfoFileName)
|
||||||
|
accessor.setHidden(encInfoFileName, true)
|
||||||
|
|
||||||
|
val writer = accessor.openWrite(encInfoFileName)
|
||||||
|
try {
|
||||||
|
_jackson.writeValue(writer, enc)
|
||||||
|
}
|
||||||
|
catch (e: Exception) {
|
||||||
|
TODO("Это никогда не должно произойти")
|
||||||
|
}
|
||||||
|
writer.close()
|
||||||
|
_encInfo.value = enc
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun rename(newName: String) {
|
override suspend fun rename(newName: String) {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val ENC_INFO_FILE_POSTFIX = ".enc-info"
|
||||||
|
private val _jackson = jacksonObjectMapper().apply { findAndRegisterModules() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -10,9 +10,9 @@ import com.github.nullptroma.wallenc.domain.datatypes.DataPackage
|
|||||||
import com.github.nullptroma.wallenc.domain.datatypes.DataPage
|
import com.github.nullptroma.wallenc.domain.datatypes.DataPage
|
||||||
import com.github.nullptroma.wallenc.domain.interfaces.IDirectory
|
import com.github.nullptroma.wallenc.domain.interfaces.IDirectory
|
||||||
import com.github.nullptroma.wallenc.domain.interfaces.IFile
|
import com.github.nullptroma.wallenc.domain.interfaces.IFile
|
||||||
|
import com.github.nullptroma.wallenc.domain.interfaces.IMetaInfo
|
||||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorageAccessor
|
import com.github.nullptroma.wallenc.domain.interfaces.IStorageAccessor
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
@@ -20,13 +20,13 @@ import kotlinx.coroutines.flow.SharedFlow
|
|||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
import java.time.Clock
|
||||||
import kotlin.io.path.Path
|
import kotlin.io.path.Path
|
||||||
import kotlin.io.path.absolute
|
import kotlin.io.path.absolute
|
||||||
import kotlin.io.path.fileSize
|
import kotlin.io.path.fileSize
|
||||||
@@ -38,7 +38,6 @@ class LocalStorageAccessor(
|
|||||||
private val ioDispatcher: CoroutineDispatcher
|
private val ioDispatcher: CoroutineDispatcher
|
||||||
) : IStorageAccessor {
|
) : IStorageAccessor {
|
||||||
private val _filesystemBasePath: Path = Path(filesystemBasePath).normalize().absolute()
|
private val _filesystemBasePath: Path = Path(filesystemBasePath).normalize().absolute()
|
||||||
private val _jackson = jacksonObjectMapper().apply { findAndRegisterModules() }
|
|
||||||
|
|
||||||
private val _size = MutableStateFlow<Long?>(null)
|
private val _size = MutableStateFlow<Long?>(null)
|
||||||
override val size: StateFlow<Long?> = _size
|
override val size: StateFlow<Long?> = _size
|
||||||
@@ -55,11 +54,9 @@ class LocalStorageAccessor(
|
|||||||
private val _dirsUpdates = MutableSharedFlow<DataPage<IDirectory>>()
|
private val _dirsUpdates = MutableSharedFlow<DataPage<IDirectory>>()
|
||||||
override val dirsUpdates: SharedFlow<DataPage<IDirectory>> = _dirsUpdates
|
override val dirsUpdates: SharedFlow<DataPage<IDirectory>> = _dirsUpdates
|
||||||
|
|
||||||
init {
|
suspend fun init() {
|
||||||
// запускам сканирование хранилища
|
// запускам сканирование хранилища
|
||||||
CoroutineScope(ioDispatcher).launch {
|
scanSizeAndNumOfFiles()
|
||||||
scanSizeAndNumOfFiles()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -201,6 +198,10 @@ class LocalStorageAccessor(
|
|||||||
val filePath = Path(filesystemBasePath.pathString, storagePath)
|
val filePath = Path(filesystemBasePath.pathString, storagePath)
|
||||||
return from(filesystemBasePath, filePath.toFile())
|
return from(filesystemBasePath, filePath.toFile())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun from(filesystemBasePath: Path, meta: IMetaInfo): LocalStorageFilePair? {
|
||||||
|
return from(filesystemBasePath, meta.path)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,7 +228,7 @@ class LocalStorageAccessor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val pair = LocalStorageFilePair.from(_filesystemBasePath, file)
|
val pair = LocalStorageFilePair.from(_filesystemBasePath, file)
|
||||||
if(pair != null) {
|
if (pair != null) {
|
||||||
workedFiles.add(pair.file.absolutePath)
|
workedFiles.add(pair.file.absolutePath)
|
||||||
workedMetaFiles.add(pair.metaFile.absolutePath)
|
workedMetaFiles.add(pair.metaFile.absolutePath)
|
||||||
|
|
||||||
@@ -259,7 +260,7 @@ class LocalStorageAccessor(
|
|||||||
size += CommonFile.metaInfo.size
|
size += CommonFile.metaInfo.size
|
||||||
numOfFiles++
|
numOfFiles++
|
||||||
|
|
||||||
if(numOfFiles % DATA_PAGE_LENGTH == 0) {
|
if (numOfFiles % DATA_PAGE_LENGTH == 0) {
|
||||||
_size.value = size
|
_size.value = size
|
||||||
_numberOfFiles.value = numOfFiles
|
_numberOfFiles.value = numOfFiles
|
||||||
}
|
}
|
||||||
@@ -379,22 +380,58 @@ class LocalStorageAccessor(
|
|||||||
emit(page)
|
emit(page)
|
||||||
}.flowOn(ioDispatcher)
|
}.flowOn(ioDispatcher)
|
||||||
|
|
||||||
private fun writeMeta(metaFile: File, meta: CommonMetaInfo) {
|
override suspend fun getFileInfo(path: String): IFile {
|
||||||
|
val pair = LocalStorageFilePair.from(_filesystemBasePath, path)
|
||||||
|
?: throw Exception("Что то пошло не так") // TODO
|
||||||
|
return CommonFile(
|
||||||
|
metaInfo = pair.meta,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getDirInfo(path: String): IDirectory {
|
||||||
|
val pair = LocalStorageFilePair.from(_filesystemBasePath, path)
|
||||||
|
?: throw Exception("Что то пошло не так") // TODO
|
||||||
|
return CommonDirectory(
|
||||||
|
metaInfo = pair.meta,
|
||||||
|
elementsCount = null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun setHidden(path: String, hidden: Boolean) {
|
||||||
|
val pair = LocalStorageFilePair.from(_filesystemBasePath, path)
|
||||||
|
?: throw Exception("Что то пошло не так") // TODO
|
||||||
|
if(pair.meta.isHidden == hidden)
|
||||||
|
return
|
||||||
|
val newMeta = pair.meta.copy(isHidden = hidden)
|
||||||
|
writeMeta(pair.metaFile, newMeta)
|
||||||
|
_filesUpdates.emit(
|
||||||
|
DataPage(
|
||||||
|
list = listOf(CommonFile(
|
||||||
|
metaInfo = newMeta
|
||||||
|
)),
|
||||||
|
pageLength = 1,
|
||||||
|
pageIndex = 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun writeMeta(metaFile: File, meta: IMetaInfo) {
|
||||||
_jackson.writeValue(metaFile, meta)
|
_jackson.writeValue(metaFile, meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createFile(storagePath: String): CommonFile {
|
private fun createFile(storagePath: String): CommonFile {
|
||||||
val path = Path(_filesystemBasePath.pathString, storagePath)
|
val path = Path(_filesystemBasePath.pathString, storagePath)
|
||||||
val file = path.toFile()
|
val file = path.toFile()
|
||||||
if(file.exists() && file.isDirectory) {
|
if (file.exists() && file.isDirectory) {
|
||||||
throw Exception("Что то пошло не так") // TODO
|
throw Exception("Что то пошло не так") // TODO
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
file.createNewFile()
|
file.createNewFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
val pair = LocalStorageFilePair.from(_filesystemBasePath, file) ?: throw Exception("Что то пошло не так") // TODO
|
val pair = LocalStorageFilePair.from(_filesystemBasePath, file)
|
||||||
val newMeta = pair.meta.copy(lastModified = java.time.Clock.systemUTC().instant())
|
?: throw Exception("Что то пошло не так") // TODO
|
||||||
|
val newMeta = pair.meta.copy(lastModified = Clock.systemUTC().instant())
|
||||||
writeMeta(pair.metaFile, newMeta)
|
writeMeta(pair.metaFile, newMeta)
|
||||||
return CommonFile(newMeta)
|
return CommonFile(newMeta)
|
||||||
}
|
}
|
||||||
@@ -402,15 +439,15 @@ class LocalStorageAccessor(
|
|||||||
private fun createDir(storagePath: String): CommonDirectory {
|
private fun createDir(storagePath: String): CommonDirectory {
|
||||||
val path = Path(_filesystemBasePath.pathString, storagePath)
|
val path = Path(_filesystemBasePath.pathString, storagePath)
|
||||||
val file = path.toFile()
|
val file = path.toFile()
|
||||||
if(file.exists() && !file.isDirectory) {
|
if (file.exists() && !file.isDirectory) {
|
||||||
throw Exception("Что то пошло не так") // TODO
|
throw Exception("Что то пошло не так") // TODO
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Files.createDirectories(path)
|
Files.createDirectories(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
val pair = LocalStorageFilePair.from(_filesystemBasePath, file) ?: throw Exception("Что то пошло не так") // TODO
|
val pair = LocalStorageFilePair.from(_filesystemBasePath, file)
|
||||||
val newMeta = pair.meta.copy(lastModified = java.time.Clock.systemUTC().instant())
|
?: throw Exception("Что то пошло не так") // TODO
|
||||||
|
val newMeta = pair.meta.copy(lastModified = Clock.systemUTC().instant())
|
||||||
writeMeta(pair.metaFile, newMeta)
|
writeMeta(pair.metaFile, newMeta)
|
||||||
return CommonDirectory(newMeta, 0)
|
return CommonDirectory(newMeta, 0)
|
||||||
}
|
}
|
||||||
@@ -425,7 +462,7 @@ class LocalStorageAccessor(
|
|||||||
|
|
||||||
override suspend fun delete(path: String) = withContext(ioDispatcher) {
|
override suspend fun delete(path: String) = withContext(ioDispatcher) {
|
||||||
val pair = LocalStorageFilePair.from(_filesystemBasePath, path)
|
val pair = LocalStorageFilePair.from(_filesystemBasePath, path)
|
||||||
if(pair != null) {
|
if (pair != null) {
|
||||||
pair.file.delete()
|
pair.file.delete()
|
||||||
pair.metaFile.delete()
|
pair.metaFile.delete()
|
||||||
}
|
}
|
||||||
@@ -433,17 +470,20 @@ class LocalStorageAccessor(
|
|||||||
|
|
||||||
override suspend fun openWrite(path: String): OutputStream = withContext(ioDispatcher) {
|
override suspend fun openWrite(path: String): OutputStream = withContext(ioDispatcher) {
|
||||||
touchFile(path)
|
touchFile(path)
|
||||||
val pair = LocalStorageFilePair.from(_filesystemBasePath, path) ?: throw Exception("Файла нет") // TODO
|
val pair = LocalStorageFilePair.from(_filesystemBasePath, path)
|
||||||
|
?: throw Exception("Файла нет") // TODO
|
||||||
return@withContext pair.file.outputStream()
|
return@withContext pair.file.outputStream()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun openRead(path: String): InputStream = withContext(ioDispatcher) {
|
override suspend fun openRead(path: String): InputStream = withContext(ioDispatcher) {
|
||||||
val pair = LocalStorageFilePair.from(_filesystemBasePath, path) ?: throw Exception("Файла нет") // TODO
|
val pair = LocalStorageFilePair.from(_filesystemBasePath, path)
|
||||||
|
?: throw Exception("Файла нет") // TODO
|
||||||
return@withContext pair.file.inputStream()
|
return@withContext pair.file.inputStream()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun moveToTrash(path: String) = withContext(ioDispatcher) {
|
override suspend fun moveToTrash(path: String) = withContext(ioDispatcher) {
|
||||||
val pair = LocalStorageFilePair.from(_filesystemBasePath, path) ?: throw Exception("Файла нет") // TODO
|
val pair = LocalStorageFilePair.from(_filesystemBasePath, path)
|
||||||
|
?: throw Exception("Файла нет") // TODO
|
||||||
val newMeta = pair.meta.copy(isDeleted = true)
|
val newMeta = pair.meta.copy(isDeleted = true)
|
||||||
writeMeta(pair.metaFile, newMeta)
|
writeMeta(pair.metaFile, newMeta)
|
||||||
}
|
}
|
||||||
@@ -451,5 +491,6 @@ class LocalStorageAccessor(
|
|||||||
companion object {
|
companion object {
|
||||||
private const val META_INFO_POSTFIX = ".wallenc-meta"
|
private const val META_INFO_POSTFIX = ".wallenc-meta"
|
||||||
private const val DATA_PAGE_LENGTH = 10
|
private const val DATA_PAGE_LENGTH = 10
|
||||||
|
private val _jackson = jacksonObjectMapper().apply { findAndRegisterModules() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.github.nullptroma.wallenc.data.vaults.local
|
package com.github.nullptroma.wallenc.data.vaults.local
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
|
import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo
|
||||||
import com.github.nullptroma.wallenc.domain.enums.VaultType
|
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.IVault
|
import com.github.nullptroma.wallenc.domain.interfaces.IVault
|
||||||
@@ -44,7 +44,7 @@ class LocalVault(private val ioDispatcher: CoroutineDispatcher, context: Context
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readStorages() {
|
private suspend fun readStorages() {
|
||||||
val path = _path.value
|
val path = _path.value
|
||||||
if (path == null || !_isAvailable.value)
|
if (path == null || !_isAvailable.value)
|
||||||
return
|
return
|
||||||
@@ -53,12 +53,12 @@ class LocalVault(private val ioDispatcher: CoroutineDispatcher, context: Context
|
|||||||
if (dirs != null) {
|
if (dirs != null) {
|
||||||
_storages.value = dirs.map {
|
_storages.value = dirs.map {
|
||||||
val uuid = UUID.fromString(it.name)
|
val uuid = UUID.fromString(it.name)
|
||||||
LocalStorage(uuid, false, it.path, ioDispatcher)
|
return@map LocalStorage(uuid, it.path, ioDispatcher).apply { init() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun createStorage(): IStorage = withContext(ioDispatcher) {
|
override suspend fun createStorage(): LocalStorage = withContext(ioDispatcher) {
|
||||||
val path = _path.value
|
val path = _path.value
|
||||||
if (path == null || !_isAvailable.value)
|
if (path == null || !_isAvailable.value)
|
||||||
throw Exception("Not available")
|
throw Exception("Not available")
|
||||||
@@ -66,7 +66,8 @@ class LocalVault(private val ioDispatcher: CoroutineDispatcher, context: Context
|
|||||||
val uuid = UUID.randomUUID()
|
val uuid = UUID.randomUUID()
|
||||||
val next = Path(path.path, uuid.toString())
|
val next = Path(path.path, uuid.toString())
|
||||||
next.createDirectory()
|
next.createDirectory()
|
||||||
val newStorage = LocalStorage(uuid, false, next.pathString, ioDispatcher)
|
val newStorage = LocalStorage(uuid, next.pathString, ioDispatcher)
|
||||||
|
newStorage.init()
|
||||||
_storages.value = _storages.value.toMutableList().apply {
|
_storages.value = _storages.value.toMutableList().apply {
|
||||||
add(newStorage)
|
add(newStorage)
|
||||||
}
|
}
|
||||||
@@ -74,15 +75,9 @@ class LocalVault(private val ioDispatcher: CoroutineDispatcher, context: Context
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun createStorage(
|
override suspend fun createStorage(
|
||||||
key: EncryptKey
|
enc: StorageEncryptionInfo
|
||||||
): IStorage = withContext(ioDispatcher) {
|
): LocalStorage = withContext(ioDispatcher) {
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun createStorage(
|
|
||||||
key: EncryptKey,
|
|
||||||
uuid: UUID
|
|
||||||
): IStorage = withContext(ioDispatcher) {
|
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.github.nullptroma.wallenc.domain.common.impl
|
package com.github.nullptroma.wallenc.domain.common.impl
|
||||||
|
|
||||||
import com.github.nullptroma.wallenc.domain.interfaces.IFile
|
import com.github.nullptroma.wallenc.domain.interfaces.IFile
|
||||||
|
import com.github.nullptroma.wallenc.domain.interfaces.IMetaInfo
|
||||||
|
|
||||||
data class CommonFile(override val metaInfo: CommonMetaInfo) : IFile
|
data class CommonFile(override val metaInfo: IMetaInfo) : IFile
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package com.github.nullptroma.wallenc.domain.datatypes
|
||||||
|
|
||||||
|
data class StorageEncryptionInfo(
|
||||||
|
val isEncrypted: Boolean,
|
||||||
|
val encryptedTestData: String?
|
||||||
|
)
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.github.nullptroma.wallenc.domain.encrypt
|
package com.github.nullptroma.wallenc.domain.encrypt
|
||||||
|
|
||||||
import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
|
import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
|
||||||
|
import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo
|
||||||
import com.github.nullptroma.wallenc.domain.interfaces.ILogger
|
import com.github.nullptroma.wallenc.domain.interfaces.ILogger
|
||||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
|
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
|
||||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorageAccessor
|
import com.github.nullptroma.wallenc.domain.interfaces.IStorageAccessor
|
||||||
@@ -13,7 +14,6 @@ class EncryptedStorage(
|
|||||||
key: EncryptKey,
|
key: EncryptKey,
|
||||||
logger: ILogger,
|
logger: ILogger,
|
||||||
ioDispatcher: CoroutineDispatcher,
|
ioDispatcher: CoroutineDispatcher,
|
||||||
override val isEncrypted: Boolean
|
|
||||||
) : IStorage {
|
) : IStorage {
|
||||||
override val size: StateFlow<Long?>
|
override val size: StateFlow<Long?>
|
||||||
get() = TODO("Not yet implemented")
|
get() = TODO("Not yet implemented")
|
||||||
@@ -25,6 +25,8 @@ class EncryptedStorage(
|
|||||||
get() = TODO("Not yet implemented")
|
get() = TODO("Not yet implemented")
|
||||||
override val isAvailable: StateFlow<Boolean>
|
override val isAvailable: StateFlow<Boolean>
|
||||||
get() = TODO("Not yet implemented")
|
get() = TODO("Not yet implemented")
|
||||||
|
override val encInfo: StateFlow<StorageEncryptionInfo>
|
||||||
|
get() = TODO("Not yet implemented")
|
||||||
override val accessor: IStorageAccessor =
|
override val accessor: IStorageAccessor =
|
||||||
EncryptedStorageAccessor(source.accessor, key, logger, ioDispatcher)
|
EncryptedStorageAccessor(source.accessor, key, logger, ioDispatcher)
|
||||||
|
|
||||||
|
|||||||
@@ -191,6 +191,22 @@ class EncryptedStorageAccessor(
|
|||||||
return flow
|
return flow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getFileInfo(path: String): IFile {
|
||||||
|
val file = source.getFileInfo(encryptPath(path))
|
||||||
|
val meta = decryptMeta(file.metaInfo)
|
||||||
|
return CommonFile(meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getDirInfo(path: String): IDirectory {
|
||||||
|
val dir = source.getDirInfo(encryptPath(path))
|
||||||
|
val meta = decryptMeta(dir.metaInfo)
|
||||||
|
return CommonDirectory(meta, dir.elementsCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun setHidden(path: String, hidden: Boolean) {
|
||||||
|
source.setHidden(encryptPath(path), hidden)
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun touchFile(path: String) {
|
override suspend fun touchFile(path: String) {
|
||||||
source.touchFile(encryptPath(path))
|
source.touchFile(encryptPath(path))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,9 @@ interface IStorageAccessor {
|
|||||||
* @return Поток директорий
|
* @return Поток директорий
|
||||||
*/
|
*/
|
||||||
fun getDirsFlow(path: String): Flow<DataPackage<List<IDirectory>>>
|
fun getDirsFlow(path: String): Flow<DataPackage<List<IDirectory>>>
|
||||||
|
suspend fun getFileInfo(path: String): IFile
|
||||||
|
suspend fun getDirInfo(path: String): IDirectory
|
||||||
|
suspend fun setHidden(path: String, hidden: Boolean)
|
||||||
suspend fun touchFile(path: String)
|
suspend fun touchFile(path: String)
|
||||||
suspend fun touchDir(path: String)
|
suspend fun touchDir(path: String)
|
||||||
suspend fun delete(path: String)
|
suspend fun delete(path: String)
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
package com.github.nullptroma.wallenc.domain.interfaces
|
package com.github.nullptroma.wallenc.domain.interfaces
|
||||||
|
|
||||||
|
import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
sealed interface IStorageInfo {
|
sealed interface IStorageInfo {
|
||||||
|
val uuid: UUID
|
||||||
|
val isAvailable: StateFlow<Boolean>
|
||||||
val size: StateFlow<Long?>
|
val size: StateFlow<Long?>
|
||||||
val numberOfFiles: StateFlow<Int?>
|
val numberOfFiles: StateFlow<Int?>
|
||||||
val uuid: UUID
|
val encInfo: StateFlow<StorageEncryptionInfo?>
|
||||||
val isEncrypted: Boolean
|
val name: StateFlow<String?>
|
||||||
val name: StateFlow<String>
|
|
||||||
val isAvailable: StateFlow<Boolean>
|
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
package com.github.nullptroma.wallenc.domain.interfaces
|
package com.github.nullptroma.wallenc.domain.interfaces
|
||||||
|
|
||||||
import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
|
import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
interface IVault : IVaultInfo {
|
interface IVault : IVaultInfo {
|
||||||
override val storages: StateFlow<List<IStorage>>
|
override val storages: StateFlow<List<IStorage>>
|
||||||
|
|
||||||
suspend fun createStorage(): IStorage
|
suspend fun createStorage(): IStorage
|
||||||
suspend fun createStorage(key: EncryptKey): IStorage
|
suspend fun createStorage(enc: StorageEncryptionInfo): IStorage
|
||||||
suspend fun createStorage(key: EncryptKey, uuid: UUID): IStorage
|
|
||||||
suspend fun remove(storage: IStorage)
|
suspend fun remove(storage: IStorage)
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user