Мета информация о хранилищах хранится в бд
This commit is contained in:
@@ -19,6 +19,6 @@ class ExampleInstrumentedTest {
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("com.github.nullptroma.wallenc", appContext.packageName)
|
||||
assertEquals("com.github.nullptroma.wallenc.app", appContext.packageName)
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import android.content.Context
|
||||
import com.github.nullptroma.wallenc.data.db.RoomFactory
|
||||
import com.github.nullptroma.wallenc.data.db.app.IAppDb
|
||||
import com.github.nullptroma.wallenc.data.db.app.dao.StorageKeyMapDao
|
||||
import com.github.nullptroma.wallenc.data.db.app.dao.StorageMetaInfoDao
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
@@ -25,6 +26,12 @@ class RoomModule {
|
||||
return database.storageKeyMapDao
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideStorageMetaInfoDao(database: IAppDb): StorageMetaInfoDao {
|
||||
return database.storageMetaInfoDao
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAppDb(
|
||||
|
||||
@@ -3,8 +3,10 @@ package com.github.nullptroma.wallenc.app.di.modules.data
|
||||
import android.content.Context
|
||||
import com.github.nullptroma.wallenc.app.di.modules.app.IoDispatcher
|
||||
import com.github.nullptroma.wallenc.data.db.app.dao.StorageKeyMapDao
|
||||
import com.github.nullptroma.wallenc.data.db.app.dao.StorageMetaInfoDao
|
||||
import com.github.nullptroma.wallenc.data.db.app.repository.StorageKeyMapRepository
|
||||
import com.github.nullptroma.wallenc.data.vaults.UnlockManager
|
||||
import com.github.nullptroma.wallenc.data.db.app.repository.StorageMetaInfoRepository
|
||||
import com.github.nullptroma.wallenc.data.storages.UnlockManager
|
||||
import com.github.nullptroma.wallenc.data.vaults.VaultsManager
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IUnlockManager
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager
|
||||
@@ -21,24 +23,42 @@ import javax.inject.Singleton
|
||||
class SingletonModule {
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideVaultsManager(@IoDispatcher ioDispatcher: CoroutineDispatcher,
|
||||
@ApplicationContext context: Context): IVaultsManager {
|
||||
fun provideVaultsManager(
|
||||
@IoDispatcher ioDispatcher: CoroutineDispatcher,
|
||||
@ApplicationContext context: Context
|
||||
): IVaultsManager {
|
||||
return VaultsManager(ioDispatcher, context)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideStorageKeyMapRepository(dao: StorageKeyMapDao): StorageKeyMapRepository {
|
||||
return StorageKeyMapRepository(dao)
|
||||
fun provideStorageKeyMapRepository(
|
||||
dao: StorageKeyMapDao,
|
||||
@IoDispatcher ioDispatcher: CoroutineDispatcher
|
||||
): StorageKeyMapRepository {
|
||||
return StorageKeyMapRepository(dao, ioDispatcher)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideUnlockManager(@IoDispatcher ioDispatcher: CoroutineDispatcher,
|
||||
repo: StorageKeyMapRepository,
|
||||
vaultsManager: IVaultsManager): IUnlockManager {
|
||||
fun provideStorageMetaInfoRepository(
|
||||
dao: StorageMetaInfoDao,
|
||||
@IoDispatcher ioDispatcher: CoroutineDispatcher
|
||||
): StorageMetaInfoRepository {
|
||||
return StorageMetaInfoRepository(dao, ioDispatcher)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideUnlockManager(
|
||||
@IoDispatcher ioDispatcher: CoroutineDispatcher,
|
||||
keyRepo: StorageKeyMapRepository,
|
||||
metaRepo: StorageMetaInfoRepository,
|
||||
vaultsManager: IVaultsManager
|
||||
): IUnlockManager {
|
||||
return UnlockManager(
|
||||
repo = repo,
|
||||
keymapRepository = keyRepo,
|
||||
metaInfoRepository = metaRepo,
|
||||
ioDispatcher = ioDispatcher,
|
||||
vaultsManager = vaultsManager
|
||||
)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.github.nullptroma.wallenc.app.di.modules.domain
|
||||
|
||||
import com.github.nullptroma.wallenc.data.vaults.UnlockManager
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IUnlockManager
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager
|
||||
import com.github.nullptroma.wallenc.domain.usecases.GetOpenedStoragesUseCase
|
||||
|
||||
@@ -3,13 +3,17 @@ package com.github.nullptroma.wallenc.data.db.app
|
||||
import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
import com.github.nullptroma.wallenc.data.db.app.dao.StorageKeyMapDao
|
||||
import com.github.nullptroma.wallenc.data.db.app.dao.StorageMetaInfoDao
|
||||
import com.github.nullptroma.wallenc.data.db.app.model.DbStorageKeyMap
|
||||
import com.github.nullptroma.wallenc.data.db.app.model.DbStorageMetaInfo
|
||||
|
||||
interface IAppDb {
|
||||
val storageKeyMapDao: StorageKeyMapDao
|
||||
val storageMetaInfoDao: StorageMetaInfoDao
|
||||
}
|
||||
|
||||
@Database(entities = [DbStorageKeyMap::class], version = 2, exportSchema = false)
|
||||
@Database(entities = [DbStorageKeyMap::class, DbStorageMetaInfo::class], version = 2, exportSchema = false)
|
||||
abstract class AppDb : IAppDb, RoomDatabase() {
|
||||
abstract override val storageKeyMapDao: StorageKeyMapDao
|
||||
abstract override val storageMetaInfoDao: StorageMetaInfoDao
|
||||
}
|
||||
@@ -12,11 +12,11 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
@Dao
|
||||
interface StorageKeyMapDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun add(keymap: DbStorageKeyMap)
|
||||
suspend fun add(keymap: DbStorageKeyMap)
|
||||
|
||||
@Query("SELECT * FROM storage_key_maps")
|
||||
fun getAll(): List<DbStorageKeyMap>
|
||||
suspend fun getAll(): List<DbStorageKeyMap>
|
||||
|
||||
@Delete
|
||||
fun delete(keymap: DbStorageKeyMap)
|
||||
suspend fun delete(keymap: DbStorageKeyMap)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.github.nullptroma.wallenc.data.db.app.dao
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import com.github.nullptroma.wallenc.data.db.app.model.DbStorageKeyMap
|
||||
import com.github.nullptroma.wallenc.data.db.app.model.DbStorageMetaInfo
|
||||
import com.github.nullptroma.wallenc.domain.common.impl.CommonStorageMetaInfo
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import java.util.UUID
|
||||
|
||||
@Dao
|
||||
interface StorageMetaInfoDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun add(metaInfo: DbStorageMetaInfo)
|
||||
|
||||
@Query("SELECT * FROM storage_meta_infos")
|
||||
suspend fun getAll(): List<DbStorageMetaInfo>
|
||||
|
||||
@Query("SELECT * FROM storage_meta_infos")
|
||||
fun getAllFlow(): Flow<List<DbStorageMetaInfo>>
|
||||
|
||||
@Query("SELECT * FROM storage_meta_infos WHERE uuid == :uuid")
|
||||
fun getMetaInfoFlow(uuid: UUID): Flow<DbStorageMetaInfo>
|
||||
|
||||
@Query("SELECT * FROM storage_meta_infos WHERE uuid == :uuid")
|
||||
suspend fun getMetaInfo(uuid: UUID): DbStorageMetaInfo?
|
||||
|
||||
@Delete
|
||||
suspend fun delete(metaInfo: DbStorageMetaInfo)
|
||||
}
|
||||
@@ -9,14 +9,14 @@ import java.util.UUID
|
||||
|
||||
@Entity(tableName = "storage_key_maps", primaryKeys = [ "source_uuid", "dest_uuid" ])
|
||||
data class DbStorageKeyMap(
|
||||
@ColumnInfo(name = "source_uuid") val sourceUuid: String,
|
||||
@ColumnInfo(name = "dest_uuid") val destUuid: String,
|
||||
@ColumnInfo(name = "source_uuid") val sourceUuid: UUID,
|
||||
@ColumnInfo(name = "dest_uuid") val destUuid: UUID,
|
||||
@ColumnInfo(name = "key") val key: ByteArray
|
||||
) {
|
||||
fun toModel(): StorageKeyMap {
|
||||
return StorageKeyMap(
|
||||
sourceUuid = UUID.fromString(sourceUuid),
|
||||
destUuid = UUID.fromString(destUuid),
|
||||
sourceUuid = sourceUuid,
|
||||
destUuid = destUuid,
|
||||
key = EncryptKey(key)
|
||||
)
|
||||
}
|
||||
@@ -44,8 +44,8 @@ data class DbStorageKeyMap(
|
||||
companion object {
|
||||
fun fromModel(keymap: StorageKeyMap): DbStorageKeyMap {
|
||||
return DbStorageKeyMap(
|
||||
sourceUuid = keymap.sourceUuid.toString(),
|
||||
destUuid = keymap.destUuid.toString(),
|
||||
sourceUuid = keymap.sourceUuid,
|
||||
destUuid = keymap.destUuid,
|
||||
key = keymap.key.bytes
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.github.nullptroma.wallenc.data.db.app.model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import com.github.nullptroma.wallenc.domain.common.impl.CommonStorageMetaInfo
|
||||
import java.util.UUID
|
||||
|
||||
@Entity(tableName = "storage_meta_infos")
|
||||
data class DbStorageMetaInfo(
|
||||
@PrimaryKey @ColumnInfo(name = "uuid") val uuid: UUID,
|
||||
@ColumnInfo(name = "meta_info") val metaInfoJson: String
|
||||
)
|
||||
@@ -3,14 +3,20 @@ package com.github.nullptroma.wallenc.data.db.app.repository
|
||||
import com.github.nullptroma.wallenc.data.db.app.dao.StorageKeyMapDao
|
||||
import com.github.nullptroma.wallenc.data.db.app.model.DbStorageKeyMap
|
||||
import com.github.nullptroma.wallenc.data.model.StorageKeyMap
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class StorageKeyMapRepository(private val dao: StorageKeyMapDao) {
|
||||
fun getAll() = dao.getAll().map { it.toModel() }
|
||||
fun add(keymap: StorageKeyMap) {
|
||||
class StorageKeyMapRepository(
|
||||
private val dao: StorageKeyMapDao,
|
||||
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)
|
||||
}
|
||||
fun delete(keymap: StorageKeyMap) {
|
||||
|
||||
suspend fun delete(keymap: StorageKeyMap) = withContext(ioDispatcher) {
|
||||
val dbModel = DbStorageKeyMap.fromModel(keymap)
|
||||
dao.delete(dbModel)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.github.nullptroma.wallenc.data.db.app.repository
|
||||
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.github.nullptroma.wallenc.data.db.app.dao.StorageMetaInfoDao
|
||||
import com.github.nullptroma.wallenc.data.db.app.model.DbStorageMetaInfo
|
||||
import com.github.nullptroma.wallenc.domain.common.impl.CommonStorageMetaInfo
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.UUID
|
||||
|
||||
class StorageMetaInfoRepository(
|
||||
private val dao: StorageMetaInfoDao,
|
||||
private val ioDispatcher: CoroutineDispatcher
|
||||
) {
|
||||
fun getAllFlow() = dao.getAllFlow()
|
||||
suspend fun getAll() = withContext(ioDispatcher) { dao.getAll() }
|
||||
suspend fun getMeta(uuid: UUID): CommonStorageMetaInfo? = withContext(ioDispatcher) {
|
||||
val json = dao.getMetaInfo(uuid)?.metaInfoJson ?: return@withContext null
|
||||
return@withContext jackson.readValue(
|
||||
json,
|
||||
CommonStorageMetaInfo::class.java
|
||||
)
|
||||
}
|
||||
|
||||
fun observeMeta(uuid: UUID): Flow<CommonStorageMetaInfo> {
|
||||
return dao.getMetaInfoFlow(uuid)
|
||||
.map { jackson.readValue(it.metaInfoJson, CommonStorageMetaInfo::class.java) }
|
||||
}
|
||||
|
||||
suspend fun setMeta(uuid: UUID, metaInfo: CommonStorageMetaInfo) = withContext(ioDispatcher) {
|
||||
val json = jackson.writeValueAsString(metaInfo)
|
||||
dao.add(DbStorageMetaInfo(uuid, json))
|
||||
}
|
||||
|
||||
fun createSingleStorageProvider(uuid: UUID): SingleStorageMetaInfoProvider {
|
||||
return SingleStorageMetaInfoProvider(this, uuid)
|
||||
}
|
||||
|
||||
class SingleStorageMetaInfoProvider (
|
||||
private val repo: StorageMetaInfoRepository,
|
||||
val uuid: UUID
|
||||
) {
|
||||
suspend fun get(): CommonStorageMetaInfo? = repo.getMeta(uuid)
|
||||
suspend fun set(metaInfo: CommonStorageMetaInfo) = repo.setMeta(uuid, metaInfo)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val jackson = jacksonObjectMapper().apply { findAndRegisterModules() }
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
package com.github.nullptroma.wallenc.data.vaults
|
||||
package com.github.nullptroma.wallenc.data.storages
|
||||
|
||||
import com.github.nullptroma.wallenc.data.db.app.repository.StorageKeyMapRepository
|
||||
import com.github.nullptroma.wallenc.data.db.app.repository.StorageMetaInfoRepository
|
||||
import com.github.nullptroma.wallenc.data.model.StorageKeyMap
|
||||
import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
|
||||
import com.github.nullptroma.wallenc.domain.encrypt.EncryptedStorage
|
||||
import com.github.nullptroma.wallenc.data.storages.encrypt.EncryptedStorage
|
||||
import com.github.nullptroma.wallenc.domain.encrypt.Encryptor
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IUnlockManager
|
||||
@@ -20,7 +21,8 @@ import kotlinx.coroutines.withContext
|
||||
import java.util.UUID
|
||||
|
||||
class UnlockManager(
|
||||
private val repo: StorageKeyMapRepository,
|
||||
private val keymapRepository: StorageKeyMapRepository,
|
||||
private val metaInfoRepository: StorageMetaInfoRepository,
|
||||
private val ioDispatcher: CoroutineDispatcher,
|
||||
vaultsManager: IVaultsManager
|
||||
) : IUnlockManager {
|
||||
@@ -33,7 +35,7 @@ class UnlockManager(
|
||||
CoroutineScope(ioDispatcher).launch {
|
||||
vaultsManager.allStorages.collectLatest {
|
||||
mutex.lock()
|
||||
val allKeys = repo.getAll()
|
||||
val allKeys = keymapRepository.getAll()
|
||||
val allStorages = it.associateBy({ it.uuid }, { it })
|
||||
val map = _openedStorages.value?.toMutableMap() ?: mutableMapOf()
|
||||
for(keymap in allKeys) {
|
||||
@@ -49,11 +51,12 @@ class UnlockManager(
|
||||
}
|
||||
}
|
||||
|
||||
private fun createEncryptedStorage(storage: IStorage, key: EncryptKey, uuid: UUID): EncryptedStorage {
|
||||
return EncryptedStorage(
|
||||
_source = storage,
|
||||
private suspend fun createEncryptedStorage(storage: IStorage, key: EncryptKey, uuid: UUID): EncryptedStorage {
|
||||
return EncryptedStorage.create(
|
||||
source = storage,
|
||||
key = key,
|
||||
ioDispatcher = ioDispatcher,
|
||||
metaInfoProvider = metaInfoRepository.createSingleStorageProvider(uuid),
|
||||
uuid = uuid
|
||||
)
|
||||
}
|
||||
@@ -80,7 +83,7 @@ class UnlockManager(
|
||||
val encStorage = createEncryptedStorage(storage, keymap.key, keymap.destUuid)
|
||||
opened[storage.uuid] = encStorage
|
||||
_openedStorages.value = opened
|
||||
repo.add(keymap)
|
||||
keymapRepository.add(keymap)
|
||||
mutex.unlock()
|
||||
}
|
||||
|
||||
@@ -97,7 +100,7 @@ class UnlockManager(
|
||||
remove(storage.uuid)
|
||||
}
|
||||
enc.dispose()
|
||||
repo.delete(model)
|
||||
keymapRepository.delete(model)
|
||||
mutex.unlock()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package com.github.nullptroma.wallenc.data.storages.encrypt
|
||||
|
||||
import com.github.nullptroma.wallenc.data.db.app.repository.StorageMetaInfoRepository
|
||||
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.StateFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.UUID
|
||||
|
||||
class EncryptedStorage private constructor(
|
||||
private val source: IStorage,
|
||||
key: EncryptKey,
|
||||
private val ioDispatcher: CoroutineDispatcher,
|
||||
private val metaInfoProvider: StorageMetaInfoRepository.SingleStorageMetaInfoProvider,
|
||||
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()
|
||||
)
|
||||
override val metaInfo: StateFlow<IStorageMetaInfo>
|
||||
get() = _metaInfo
|
||||
override val isVirtualStorage: Boolean = true
|
||||
|
||||
override val isAvailable: StateFlow<Boolean>
|
||||
get() = source.isAvailable
|
||||
override val accessor: EncryptedStorageAccessor =
|
||||
EncryptedStorageAccessor(source.accessor, key, ioDispatcher)
|
||||
|
||||
private suspend fun init() {
|
||||
readMeta()
|
||||
}
|
||||
|
||||
private suspend fun readMeta() = withContext(ioDispatcher) {
|
||||
var meta = metaInfoProvider.get()
|
||||
if(meta == null) {
|
||||
meta = CommonStorageMetaInfo()
|
||||
metaInfoProvider.set(meta)
|
||||
}
|
||||
_metaInfo.value = meta
|
||||
}
|
||||
|
||||
override suspend fun rename(newName: String) = withContext(ioDispatcher) {
|
||||
val cur = _metaInfo.value
|
||||
val newMeta = CommonStorageMetaInfo(
|
||||
encInfo = cur.encInfo,
|
||||
name = newName
|
||||
)
|
||||
_metaInfo.value = newMeta
|
||||
metaInfoProvider.set(newMeta)
|
||||
}
|
||||
|
||||
override suspend fun setEncInfo(encInfo: StorageEncryptionInfo) = withContext(ioDispatcher) {
|
||||
val cur = _metaInfo.value
|
||||
val newMeta = CommonStorageMetaInfo(
|
||||
encInfo = encInfo,
|
||||
name = cur.name
|
||||
)
|
||||
_metaInfo.value = newMeta
|
||||
metaInfoProvider.set(newMeta)
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
accessor.dispose()
|
||||
}
|
||||
|
||||
companion object {
|
||||
suspend fun create(
|
||||
source: IStorage,
|
||||
key: EncryptKey,
|
||||
ioDispatcher: CoroutineDispatcher,
|
||||
metaInfoProvider: StorageMetaInfoRepository.SingleStorageMetaInfoProvider,
|
||||
uuid: UUID = UUID.randomUUID()
|
||||
): EncryptedStorage = withContext(ioDispatcher) {
|
||||
val storage = EncryptedStorage(
|
||||
source = source,
|
||||
key = key,
|
||||
ioDispatcher = ioDispatcher,
|
||||
metaInfoProvider = metaInfoProvider,
|
||||
uuid = uuid
|
||||
)
|
||||
storage.init()
|
||||
return@withContext storage
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
package com.github.nullptroma.wallenc.domain.encrypt
|
||||
package com.github.nullptroma.wallenc.data.storages.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.encrypt.Encryptor
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IDirectory
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IFile
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IMetaInfo
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.github.nullptroma.wallenc.data.vaults.local
|
||||
package com.github.nullptroma.wallenc.data.storages.local
|
||||
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.github.nullptroma.wallenc.domain.common.impl.CommonStorageMetaInfo
|
||||
@@ -24,14 +24,8 @@ class LocalStorage(
|
||||
override val numberOfFiles: StateFlow<Int?>
|
||||
get() = accessor.numberOfFiles
|
||||
|
||||
private val _metaInfo = MutableStateFlow(
|
||||
CommonStorageMetaInfo(
|
||||
encInfo = StorageEncryptionInfo(
|
||||
isEncrypted = false,
|
||||
encryptedTestData = null
|
||||
),
|
||||
name = null
|
||||
)
|
||||
private val _metaInfo = MutableStateFlow<IStorageMetaInfo>(
|
||||
CommonStorageMetaInfo()
|
||||
)
|
||||
override val metaInfo: StateFlow<IStorageMetaInfo>
|
||||
get() = _metaInfo
|
||||
@@ -40,49 +34,60 @@ class LocalStorage(
|
||||
get() = accessor.isAvailable
|
||||
private val _accessor = LocalStorageAccessor(absolutePath, ioDispatcher)
|
||||
override val accessor: IStorageAccessor = _accessor
|
||||
|
||||
private val encInfoFileName: String = "$uuid$ENC_INFO_FILE_POSTFIX"
|
||||
override val isVirtualStorage: Boolean = false
|
||||
private val metaInfoFileName: String = "$uuid$ENC_INFO_FILE_POSTFIX"
|
||||
|
||||
suspend fun init() {
|
||||
_accessor.init()
|
||||
readEncInfo()
|
||||
readMetaInfo()
|
||||
}
|
||||
|
||||
private suspend fun readEncInfo() = withContext(ioDispatcher) {
|
||||
var enc: StorageEncryptionInfo? = null
|
||||
private suspend fun readMetaInfo() = withContext(ioDispatcher) {
|
||||
var meta: CommonStorageMetaInfo
|
||||
var reader: InputStream? = null
|
||||
try {
|
||||
reader = _accessor.openReadSystemFile(encInfoFileName)
|
||||
enc = jackson.readValue(reader, StorageEncryptionInfo::class.java)
|
||||
reader = _accessor.openReadSystemFile(metaInfoFileName)
|
||||
meta = jackson.readValue(reader, CommonStorageMetaInfo::class.java)
|
||||
}
|
||||
catch(e: Exception) {
|
||||
// чтение не удалось, значит нужно записать файл
|
||||
enc = StorageEncryptionInfo(
|
||||
isEncrypted = false,
|
||||
encryptedTestData = null
|
||||
)
|
||||
setEncInfo(enc)
|
||||
meta = CommonStorageMetaInfo()
|
||||
updateMetaInfo(meta)
|
||||
}
|
||||
finally {
|
||||
reader?.close()
|
||||
}
|
||||
_metaInfo.value = _metaInfo.value.copy(encInfo = enc)
|
||||
_metaInfo.value = meta
|
||||
}
|
||||
|
||||
suspend fun setEncInfo(enc: StorageEncryptionInfo) = withContext(ioDispatcher) {
|
||||
val writer = _accessor.openWriteSystemFile(encInfoFileName)
|
||||
private suspend fun updateMetaInfo(meta: IStorageMetaInfo) = withContext(ioDispatcher) {
|
||||
val writer = _accessor.openWriteSystemFile(metaInfoFileName)
|
||||
try {
|
||||
jackson.writeValue(writer, enc)
|
||||
jackson.writeValue(writer, meta)
|
||||
}
|
||||
catch (e: Exception) {
|
||||
TODO("Это никогда не должно произойти")
|
||||
throw e
|
||||
}
|
||||
finally {
|
||||
writer.close()
|
||||
_metaInfo.value = _metaInfo.value.copy(encInfo = enc)
|
||||
}
|
||||
_metaInfo.value = meta
|
||||
}
|
||||
|
||||
override suspend fun rename(newName: String) {
|
||||
TODO("Not yet implemented")
|
||||
override suspend fun rename(newName: String) = withContext(ioDispatcher) {
|
||||
val curMeta = metaInfo.value
|
||||
updateMetaInfo(CommonStorageMetaInfo(
|
||||
encInfo = curMeta.encInfo,
|
||||
name = newName
|
||||
))
|
||||
}
|
||||
|
||||
override suspend fun setEncInfo(encInfo: StorageEncryptionInfo) = withContext(ioDispatcher) {
|
||||
val curMeta = metaInfo.value
|
||||
updateMetaInfo(CommonStorageMetaInfo(
|
||||
encInfo = encInfo,
|
||||
name = curMeta.name
|
||||
))
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.github.nullptroma.wallenc.data.vaults.local
|
||||
package com.github.nullptroma.wallenc.data.storages.local
|
||||
|
||||
import com.fasterxml.jackson.core.JacksonException
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
@@ -57,7 +57,7 @@ class LocalStorageAccessor(
|
||||
private val _dirsUpdates = MutableSharedFlow<DataPage<IDirectory>>()
|
||||
override val dirsUpdates: SharedFlow<DataPage<IDirectory>> = _dirsUpdates
|
||||
|
||||
suspend fun init() {
|
||||
suspend fun init() = withContext(ioDispatcher) {
|
||||
// запускам сканирование хранилища
|
||||
scanSizeAndNumOfFiles()
|
||||
}
|
||||
@@ -251,11 +251,11 @@ class LocalStorageAccessor(
|
||||
* Считает файлы и их размер. Не бросает исключения, если файлы недоступны
|
||||
* @throws none Если возникла ошибка, оставляет размер и количества файлов равными null
|
||||
*/
|
||||
private suspend fun scanSizeAndNumOfFiles() {
|
||||
private suspend fun scanSizeAndNumOfFiles() = withContext(ioDispatcher) {
|
||||
if (!checkAvailable()) {
|
||||
_size.value = null
|
||||
_numberOfFiles.value = null
|
||||
return
|
||||
return@withContext
|
||||
}
|
||||
|
||||
var size = 0L
|
||||
@@ -280,8 +280,8 @@ class LocalStorageAccessor(
|
||||
return@withContext listOf()
|
||||
|
||||
val list = mutableListOf<IFile>()
|
||||
scanStorage(baseStoragePath = "/", maxDepth = -1, fileCallback = { _, CommonFile ->
|
||||
list.add(CommonFile)
|
||||
scanStorage(baseStoragePath = "/", maxDepth = -1, fileCallback = { _, commonFile ->
|
||||
list.add(commonFile)
|
||||
})
|
||||
return@withContext list
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.github.nullptroma.wallenc.data.vaults.local
|
||||
package com.github.nullptroma.wallenc.data.vaults
|
||||
|
||||
import android.content.Context
|
||||
import com.github.nullptroma.wallenc.data.storages.local.LocalStorage
|
||||
import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo
|
||||
import com.github.nullptroma.wallenc.domain.enums.VaultType
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.github.nullptroma.wallenc.data.vaults
|
||||
|
||||
import android.content.Context
|
||||
import com.github.nullptroma.wallenc.data.vaults.local.LocalVault
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IVault
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager
|
||||
|
||||
@@ -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
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -9,4 +9,5 @@ sealed interface IStorageInfo {
|
||||
val size: StateFlow<Long?>
|
||||
val numberOfFiles: StateFlow<Int?>
|
||||
val metaInfo: StateFlow<IStorageMetaInfo>
|
||||
val isVirtualStorage: Boolean
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[versions]
|
||||
agp = "8.8.0"
|
||||
jacksonModuleKotlin = "2.18.2"
|
||||
kotlin = "2.0.10"
|
||||
kotlin = "2.0.20"
|
||||
coreKtx = "1.15.0"
|
||||
junit = "4.13.2"
|
||||
junitVersion = "1.2.1"
|
||||
@@ -17,12 +17,11 @@ hiltNavigation = "1.2.0"
|
||||
timber = "5.0.1"
|
||||
yandexAuthSdk = "3.1.2"
|
||||
daggerHilt = "2.52"
|
||||
ksp = "2.0.10-1.0.24"
|
||||
ksp = "2.0.20-1.0.25"
|
||||
room = "2.6.1"
|
||||
retrofit = "2.11.0"
|
||||
appcompat = "1.7.0"
|
||||
material = "1.12.0"
|
||||
runtimeAndroid = "1.7.5"
|
||||
|
||||
[libraries]
|
||||
jackson-datatype-jsr310 = { module = "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" }
|
||||
|
||||
@@ -44,14 +44,14 @@ fun LocalVaultScreen(modifier: Modifier = Modifier,
|
||||
detectTapGestures(
|
||||
onTap = { _ -> viewModel.printStorageInfoToLog(it) }
|
||||
)
|
||||
}) {
|
||||
}.padding(8.dp)) {
|
||||
val available by it.isAvailable.collectAsStateWithLifecycle()
|
||||
val numOfFiles by it.numberOfFiles.collectAsStateWithLifecycle()
|
||||
val size by it.size.collectAsStateWithLifecycle()
|
||||
val metaInfo by it.metaInfo.collectAsStateWithLifecycle()
|
||||
|
||||
val enc = metaInfo.encInfo
|
||||
Column {
|
||||
Column(modifier = Modifier.padding(4.dp)) {
|
||||
Text(it.uuid.toString())
|
||||
Text("IsAvailable: $available")
|
||||
Text("Files: $numOfFiles")
|
||||
|
||||
Reference in New Issue
Block a user