Статичный IV для имён файлов
This commit is contained in:
@@ -10,11 +10,11 @@ import com.github.nullptroma.wallenc.data.db.app.model.DbStorageKeyMap
|
||||
@Dao
|
||||
interface StorageKeyMapDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun add(keymap: DbStorageKeyMap)
|
||||
suspend fun add(vararg keymaps: DbStorageKeyMap)
|
||||
|
||||
@Query("SELECT * FROM storage_key_maps")
|
||||
suspend fun getAll(): List<DbStorageKeyMap>
|
||||
|
||||
@Delete
|
||||
suspend fun delete(keymap: DbStorageKeyMap)
|
||||
suspend fun delete(vararg keymaps: DbStorageKeyMap)
|
||||
}
|
||||
@@ -11,13 +11,13 @@ class StorageKeyMapRepository(
|
||||
private val ioDispatcher: CoroutineDispatcher
|
||||
) {
|
||||
suspend fun getAll() = withContext(ioDispatcher) { dao.getAll().map { it.toModel() } }
|
||||
suspend fun add(keymap: StorageKeyMap) = withContext(ioDispatcher) {
|
||||
val dbModel = DbStorageKeyMap.fromModel(keymap)
|
||||
dao.add(dbModel)
|
||||
suspend fun add(vararg keymaps: StorageKeyMap) = withContext(ioDispatcher) {
|
||||
val dbModels = keymaps.map { DbStorageKeyMap.fromModel(it) }
|
||||
dao.add(*dbModels.toTypedArray())
|
||||
}
|
||||
|
||||
suspend fun delete(keymap: StorageKeyMap) = withContext(ioDispatcher) {
|
||||
val dbModel = DbStorageKeyMap.fromModel(keymap)
|
||||
dao.delete(dbModel)
|
||||
suspend fun delete(vararg keymaps: StorageKeyMap) = withContext(ioDispatcher) {
|
||||
val dbModels = keymaps.map { DbStorageKeyMap.fromModel(it) }
|
||||
dao.delete(*dbModels.toTypedArray())
|
||||
}
|
||||
}
|
||||
@@ -36,16 +36,23 @@ class UnlockManager(
|
||||
vaultsManager.allStorages.collectLatest {
|
||||
mutex.lock()
|
||||
val allKeys = keymapRepository.getAll()
|
||||
val keysToRemove = mutableListOf<StorageKeyMap>()
|
||||
val allStorages = it.associateBy({ it.uuid }, { it })
|
||||
val map = _openedStorages.value?.toMutableMap() ?: mutableMapOf()
|
||||
for(keymap in allKeys) {
|
||||
if(map.contains(keymap.sourceUuid))
|
||||
continue
|
||||
val storage = allStorages[keymap.sourceUuid] ?: continue
|
||||
val encStorage = createEncryptedStorage(storage, keymap.key, keymap.destUuid)
|
||||
map[storage.uuid] = encStorage
|
||||
try {
|
||||
val storage = allStorages[keymap.sourceUuid] ?: continue
|
||||
val encStorage = createEncryptedStorage(storage, keymap.key, keymap.destUuid)
|
||||
map[storage.uuid] = encStorage
|
||||
}
|
||||
catch (_: Exception) {
|
||||
keysToRemove.add(keymap)
|
||||
}
|
||||
}
|
||||
_openedStorages.value = map
|
||||
keymapRepository.delete(*keysToRemove.toTypedArray()) // удалить мёртвые ключи
|
||||
mutex.unlock()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,13 @@ import com.github.nullptroma.wallenc.data.db.app.repository.StorageMetaInfoRepos
|
||||
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.encrypt.Encryptor
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorageMetaInfo
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.DisposableHandle
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -15,11 +18,15 @@ import java.util.UUID
|
||||
|
||||
class EncryptedStorage private constructor(
|
||||
private val source: IStorage,
|
||||
key: EncryptKey,
|
||||
private val ioDispatcher: CoroutineDispatcher,
|
||||
private val key: EncryptKey,
|
||||
ioDispatcher: CoroutineDispatcher,
|
||||
private val metaInfoProvider: StorageMetaInfoRepository.SingleStorageMetaInfoProvider,
|
||||
override val uuid: UUID = UUID.randomUUID()
|
||||
) : IStorage, DisposableHandle {
|
||||
private val job = Job()
|
||||
private val scope = CoroutineScope(ioDispatcher + job)
|
||||
private val encInfo = source.metaInfo.value.encInfo ?: throw Exception("Storage is not encrypted") // TODO
|
||||
|
||||
override val size: StateFlow<Long?>
|
||||
get() = source.size
|
||||
override val numberOfFiles: StateFlow<Int?>
|
||||
@@ -35,13 +42,19 @@ class EncryptedStorage private constructor(
|
||||
override val isAvailable: StateFlow<Boolean>
|
||||
get() = source.isAvailable
|
||||
override val accessor: EncryptedStorageAccessor =
|
||||
EncryptedStorageAccessor(source.accessor, key, ioDispatcher)
|
||||
EncryptedStorageAccessor(source.accessor, encInfo.pathIv, key, scope)
|
||||
|
||||
private suspend fun init() {
|
||||
checkKey()
|
||||
readMeta()
|
||||
}
|
||||
|
||||
private suspend fun readMeta() = withContext(ioDispatcher) {
|
||||
private fun checkKey() {
|
||||
if(!Encryptor.checkKey(key, encInfo))
|
||||
throw Exception("Incorrect key") // TODO
|
||||
}
|
||||
|
||||
private suspend fun readMeta() = scope.run {
|
||||
var meta = metaInfoProvider.get()
|
||||
if(meta == null) {
|
||||
meta = CommonStorageMetaInfo()
|
||||
@@ -50,7 +63,7 @@ class EncryptedStorage private constructor(
|
||||
_metaInfo.value = meta
|
||||
}
|
||||
|
||||
override suspend fun rename(newName: String) = withContext(ioDispatcher) {
|
||||
override suspend fun rename(newName: String) = scope.run {
|
||||
val cur = _metaInfo.value
|
||||
val newMeta = CommonStorageMetaInfo(
|
||||
encInfo = cur.encInfo,
|
||||
@@ -60,7 +73,7 @@ class EncryptedStorage private constructor(
|
||||
metaInfoProvider.set(newMeta)
|
||||
}
|
||||
|
||||
override suspend fun setEncInfo(encInfo: StorageEncryptionInfo) = withContext(ioDispatcher) {
|
||||
override suspend fun setEncInfo(encInfo: StorageEncryptionInfo) = scope.run {
|
||||
val cur = _metaInfo.value
|
||||
val newMeta = CommonStorageMetaInfo(
|
||||
encInfo = encInfo,
|
||||
@@ -72,6 +85,7 @@ class EncryptedStorage private constructor(
|
||||
|
||||
override fun dispose() {
|
||||
accessor.dispose()
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -89,7 +103,13 @@ class EncryptedStorage private constructor(
|
||||
metaInfoProvider = metaInfoProvider,
|
||||
uuid = uuid
|
||||
)
|
||||
storage.init()
|
||||
try {
|
||||
storage.init()
|
||||
}
|
||||
catch (e: Exception) {
|
||||
storage.dispose()
|
||||
throw e
|
||||
}
|
||||
return@withContext storage
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
package com.github.nullptroma.wallenc.data.storages.encrypt
|
||||
|
||||
import android.util.Log
|
||||
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.encrypt.Encryptor
|
||||
import com.github.nullptroma.wallenc.domain.encrypt.EncryptorWithStaticIv
|
||||
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
|
||||
@@ -27,12 +27,10 @@ import kotlin.io.path.pathString
|
||||
|
||||
class EncryptedStorageAccessor(
|
||||
private val source: IStorageAccessor,
|
||||
pathIv: ByteArray,
|
||||
key: EncryptKey,
|
||||
ioDispatcher: CoroutineDispatcher
|
||||
private val scope: CoroutineScope
|
||||
) : 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
|
||||
@@ -43,10 +41,19 @@ class EncryptedStorageAccessor(
|
||||
private val _dirsUpdates = MutableSharedFlow<DataPackage<List<IDirectory>>>()
|
||||
override val dirsUpdates: SharedFlow<DataPackage<List<IDirectory>>> = _dirsUpdates
|
||||
|
||||
private val encryptor = Encryptor(key.toAesKey())
|
||||
private val dataEncryptor = Encryptor(key.toAesKey())
|
||||
private val pathEncryptor = EncryptorWithStaticIv(key.toAesKey(), pathIv)
|
||||
|
||||
init {
|
||||
collectSourceState()
|
||||
|
||||
for(i in 1..5) {
|
||||
val orig = "/hello/path/test.txt"
|
||||
val enc = encryptPath(orig)
|
||||
val dec = decryptPath(enc)
|
||||
|
||||
Log.d("MyTag", "Path $orig to $enc to $dec")
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectSourceState() {
|
||||
@@ -63,7 +70,6 @@ class EncryptedStorageAccessor(
|
||||
}
|
||||
|
||||
launch {
|
||||
|
||||
source.dirsUpdates.collect {
|
||||
val dirs = it.data.map(::decryptEntity)
|
||||
_dirsUpdates.emit(DataPackage(
|
||||
@@ -116,7 +122,7 @@ class EncryptedStorageAccessor(
|
||||
val path = Path(pathStr)
|
||||
val segments = mutableListOf<String>()
|
||||
for (segment in path)
|
||||
segments.add(encryptor.encryptString(segment.pathString))
|
||||
segments.add(pathEncryptor.encryptString(segment.pathString))
|
||||
val res = Path("/",*(segments.toTypedArray()))
|
||||
return res.pathString
|
||||
}
|
||||
@@ -125,7 +131,7 @@ class EncryptedStorageAccessor(
|
||||
val path = Path(pathStr)
|
||||
val segments = mutableListOf<String>()
|
||||
for (segment in path)
|
||||
segments.add(encryptor.decryptString(segment.pathString))
|
||||
segments.add(pathEncryptor.decryptString(segment.pathString))
|
||||
val res = Path("/",*(segments.toTypedArray()))
|
||||
return res.pathString
|
||||
}
|
||||
@@ -198,12 +204,12 @@ class EncryptedStorageAccessor(
|
||||
|
||||
override suspend fun openWrite(path: String): OutputStream {
|
||||
val stream = source.openWrite(encryptPath(path))
|
||||
return encryptor.encryptStream(stream)
|
||||
return dataEncryptor.encryptStream(stream)
|
||||
}
|
||||
|
||||
override suspend fun openRead(path: String): InputStream {
|
||||
val stream = source.openRead(encryptPath(path))
|
||||
return encryptor.decryptStream(stream)
|
||||
return dataEncryptor.decryptStream(stream)
|
||||
}
|
||||
|
||||
override suspend fun moveToTrash(path: String) {
|
||||
@@ -211,8 +217,7 @@ class EncryptedStorageAccessor(
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
job.cancel()
|
||||
encryptor.dispose()
|
||||
dataEncryptor.dispose()
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user