Мета информация о хранилищах хранится в бд

This commit is contained in:
Пытков Роман
2025-01-25 20:19:06 +03:00
parent 8e2ac2f68d
commit d78ed70e0f
25 changed files with 328 additions and 135 deletions

View File

@@ -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

View File

@@ -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<Long?>
get() = _source.size
override val numberOfFiles: StateFlow<Int?>
get() = _source.numberOfFiles
private val _metaInfo = MutableStateFlow<IStorageMetaInfo>(
CommonStorageMetaInfo(
encInfo = StorageEncryptionInfo(
isEncrypted = false,
encryptedTestData = null
),
name = null
)
)
override val metaInfo: StateFlow<IStorageMetaInfo>
get() = _metaInfo
override val isAvailable: StateFlow<Boolean>
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()
}
}

View File

@@ -1,217 +0,0 @@
package com.github.nullptroma.wallenc.domain.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.interfaces.IDirectory
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 kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import java.io.InputStream
import java.io.OutputStream
import kotlin.io.path.Path
import kotlin.io.path.pathString
class EncryptedStorageAccessor(
private val source: IStorageAccessor,
key: EncryptKey,
ioDispatcher: CoroutineDispatcher
) : IStorageAccessor, DisposableHandle {
private val job = Job()
private val scope = CoroutineScope(ioDispatcher + job)
override val size: StateFlow<Long?> = source.size
override val numberOfFiles: StateFlow<Int?> = source.numberOfFiles
override val isAvailable: StateFlow<Boolean> = source.isAvailable
private val _filesUpdates = MutableSharedFlow<DataPackage<List<IFile>>>()
override val filesUpdates: SharedFlow<DataPackage<List<IFile>>> = _filesUpdates
private val _dirsUpdates = MutableSharedFlow<DataPackage<List<IDirectory>>>()
override val dirsUpdates: SharedFlow<DataPackage<List<IDirectory>>> = _dirsUpdates
private val encryptor = Encryptor(key.toAesKey())
init {
collectSourceState()
}
private fun collectSourceState() {
scope.launch {
launch {
source.filesUpdates.collect {
val files = it.data.map(::decryptEntity)
_filesUpdates.emit(DataPackage(
data = files,
isLoading = it.isLoading,
isError = it.isError
))
}
}
launch {
source.dirsUpdates.collect {
val dirs = it.data.map(::decryptEntity)
_dirsUpdates.emit(DataPackage(
data = dirs,
isLoading = it.isLoading,
isError = it.isError
))
}
}
}
}
private fun encryptEntity(file: IFile): IFile {
return CommonFile(encryptMeta(file.metaInfo))
}
private fun decryptEntity(file: IFile): IFile {
return CommonFile(decryptMeta(file.metaInfo))
}
private fun encryptEntity(dir: IDirectory): IDirectory {
return CommonDirectory(encryptMeta(dir.metaInfo), dir.elementsCount)
}
private fun decryptEntity(dir: IDirectory): IDirectory {
return CommonDirectory(decryptMeta(dir.metaInfo), dir.elementsCount)
}
private fun encryptMeta(meta: IMetaInfo): CommonMetaInfo {
return CommonMetaInfo(
size = meta.size,
isDeleted = meta.isDeleted,
isHidden = meta.isHidden,
lastModified = meta.lastModified,
path = encryptPath(meta.path)
)
}
private fun decryptMeta(meta: IMetaInfo): CommonMetaInfo {
return CommonMetaInfo(
size = meta.size,
isDeleted = meta.isDeleted,
isHidden = meta.isHidden,
lastModified = meta.lastModified,
path = decryptPath(meta.path)
)
}
private fun encryptPath(pathStr: String): String {
val path = Path(pathStr)
val segments = mutableListOf<String>()
for (segment in path)
segments.add(encryptor.encryptString(segment.pathString))
val res = Path("/",*(segments.toTypedArray()))
return res.pathString
}
private fun decryptPath(pathStr: String): String {
val path = Path(pathStr)
val segments = mutableListOf<String>()
for (segment in path)
segments.add(encryptor.decryptString(segment.pathString))
val res = Path("/",*(segments.toTypedArray()))
return res.pathString
}
override suspend fun getAllFiles(): List<IFile> {
return source.getAllFiles().map(::decryptEntity)
}
override suspend fun getFiles(path: String): List<IFile> {
return source.getFiles(encryptPath(path)).map(::decryptEntity)
}
override fun getFilesFlow(path: String): Flow<DataPackage<List<IFile>>> {
val flow = source.getFilesFlow(encryptPath(path)).map {
DataPackage(
data = it.data.map(::decryptEntity),
isLoading = it.isLoading,
isError = it.isError
)
}
return flow
}
override suspend fun getAllDirs(): List<IDirectory> {
return source.getAllDirs().map(::decryptEntity)
}
override suspend fun getDirs(path: String): List<IDirectory> {
return source.getDirs(encryptPath(path)).map(::decryptEntity)
}
override fun getDirsFlow(path: String): Flow<DataPackage<List<IDirectory>>> {
val flow = source.getDirsFlow(encryptPath(path)).map {
DataPackage(
data = it.data.map(::decryptEntity),
isLoading = it.isLoading,
isError = it.isError
)
}
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) {
source.touchFile(encryptPath(path))
}
override suspend fun touchDir(path: String) {
source.touchDir(encryptPath(path))
}
override suspend fun delete(path: String) {
source.delete(encryptPath(path))
}
override suspend fun openWrite(path: String): OutputStream {
val stream = source.openWrite(encryptPath(path))
return encryptor.encryptStream(stream)
}
override suspend fun openRead(path: String): InputStream {
val stream = source.openRead(encryptPath(path))
return encryptor.decryptStream(stream)
}
override suspend fun moveToTrash(path: String) {
source.moveToTrash(encryptPath(path))
}
override fun dispose() {
job.cancel()
encryptor.dispose()
}
}

View File

@@ -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)
}

View File

@@ -9,4 +9,5 @@ sealed interface IStorageInfo {
val size: StateFlow<Long?>
val numberOfFiles: StateFlow<Int?>
val metaInfo: StateFlow<IStorageMetaInfo>
val isVirtualStorage: Boolean
}

View File

@@ -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