Split key concern out of storage plugin
This creates a KeyManager interface in the new core module which the storage module can use to get the key from.
This commit is contained in:
parent
9e56384cb2
commit
27eb95f768
21 changed files with 64 additions and 72 deletions
|
@ -24,7 +24,7 @@ internal const val KEY_ALIAS_MAIN = "com.stevesoltys.seedvault.main"
|
|||
private const val KEY_ALGORITHM_BACKUP = "AES"
|
||||
private const val KEY_ALGORITHM_MAIN = "HmacSHA256"
|
||||
|
||||
interface KeyManager {
|
||||
interface KeyManager : org.calyxos.seedvault.core.crypto.KeyManager {
|
||||
/**
|
||||
* Store a new backup key derived from the given [seed].
|
||||
*
|
||||
|
@ -57,14 +57,6 @@ interface KeyManager {
|
|||
* because the key can not leave the [KeyStore]'s hardware security module.
|
||||
*/
|
||||
fun getBackupKey(): SecretKey
|
||||
|
||||
/**
|
||||
* Returns the main key, so it can be used for deriving sub-keys.
|
||||
*
|
||||
* Note that any attempt to export the key will return null or an empty [ByteArray],
|
||||
* because the key can not leave the [KeyStore]'s hardware security module.
|
||||
*/
|
||||
fun getMainKey(): SecretKey
|
||||
}
|
||||
|
||||
internal class KeyManagerImpl(
|
||||
|
|
|
@ -8,12 +8,10 @@ package com.stevesoltys.seedvault.plugins.webdav
|
|||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.provider.Settings
|
||||
import com.stevesoltys.seedvault.crypto.KeyManager
|
||||
import com.stevesoltys.seedvault.plugins.StoragePlugin
|
||||
|
||||
class WebDavFactory(
|
||||
private val context: Context,
|
||||
private val keyManager: KeyManager,
|
||||
) {
|
||||
|
||||
fun createAppStoragePlugin(config: WebDavConfig): StoragePlugin<WebDavConfig> {
|
||||
|
@ -27,7 +25,6 @@ class WebDavFactory(
|
|||
val androidId =
|
||||
Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID)
|
||||
return com.stevesoltys.seedvault.storage.WebDavStoragePlugin(
|
||||
keyManager = keyManager,
|
||||
androidId = androidId,
|
||||
webDavConfig = config,
|
||||
)
|
||||
|
|
|
@ -9,6 +9,6 @@ import org.koin.android.ext.koin.androidContext
|
|||
import org.koin.dsl.module
|
||||
|
||||
val storagePluginModuleWebDav = module {
|
||||
single { WebDavFactory(androidContext(), get()) }
|
||||
single { WebDavFactory(androidContext()) }
|
||||
single { WebDavHandler(androidContext(), get(), get(), get()) }
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import com.stevesoltys.seedvault.crypto.KeyManager
|
|||
import com.stevesoltys.seedvault.getStorageContext
|
||||
import com.stevesoltys.seedvault.plugins.saf.DocumentsStorage
|
||||
import org.calyxos.backup.storage.plugin.saf.SafStoragePlugin
|
||||
import javax.crypto.SecretKey
|
||||
|
||||
internal class SeedvaultSafStoragePlugin(
|
||||
private val appContext: Context,
|
||||
|
@ -24,6 +23,4 @@ internal class SeedvaultSafStoragePlugin(
|
|||
override val context: Context get() = appContext.getStorageContext { storage.safStorage.isUsb }
|
||||
override val root: DocumentFile get() = storage.rootBackupDir ?: error("No storage set")
|
||||
|
||||
override fun getMasterKey(): SecretKey = keyManager.getMainKey()
|
||||
override fun hasMasterKey(): Boolean = keyManager.hasMainKey()
|
||||
}
|
||||
|
|
|
@ -5,10 +5,11 @@
|
|||
|
||||
package com.stevesoltys.seedvault.storage
|
||||
|
||||
import com.stevesoltys.seedvault.crypto.KeyManager
|
||||
import com.stevesoltys.seedvault.plugins.StoragePluginManager
|
||||
import org.calyxos.backup.storage.api.StorageBackup
|
||||
import org.koin.dsl.module
|
||||
|
||||
val storageModule = module {
|
||||
single { StorageBackup(get(), { get<StoragePluginManager>().filesPlugin }) }
|
||||
single { StorageBackup(get(), { get<StoragePluginManager>().filesPlugin }, get<KeyManager>()) }
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import at.bitfire.dav4jvm.Response.HrefRelation.SELF
|
|||
import at.bitfire.dav4jvm.exception.NotFoundException
|
||||
import at.bitfire.dav4jvm.property.webdav.DisplayName
|
||||
import at.bitfire.dav4jvm.property.webdav.ResourceType
|
||||
import com.stevesoltys.seedvault.crypto.KeyManager
|
||||
import com.stevesoltys.seedvault.plugins.chunkFolderRegex
|
||||
import com.stevesoltys.seedvault.plugins.webdav.DIRECTORY_ROOT
|
||||
import com.stevesoltys.seedvault.plugins.webdav.WebDavConfig
|
||||
|
@ -26,12 +25,10 @@ import org.koin.core.time.measureDuration
|
|||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import javax.crypto.SecretKey
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
internal class WebDavStoragePlugin(
|
||||
private val keyManager: KeyManager,
|
||||
/**
|
||||
* The result of Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID)
|
||||
*/
|
||||
|
@ -121,9 +118,6 @@ internal class WebDavStoragePlugin(
|
|||
}
|
||||
}
|
||||
|
||||
override fun getMasterKey(): SecretKey = keyManager.getMainKey()
|
||||
override fun hasMasterKey(): Boolean = keyManager.hasMainKey()
|
||||
|
||||
@Throws(IOException::class)
|
||||
override suspend fun getChunkOutputStream(chunkId: String): OutputStream {
|
||||
val chunkFolderName = chunkId.substring(0, 2)
|
||||
|
|
|
@ -5,12 +5,10 @@
|
|||
|
||||
package com.stevesoltys.seedvault.storage
|
||||
|
||||
import com.stevesoltys.seedvault.crypto.KeyManager
|
||||
import com.stevesoltys.seedvault.getRandomByteArray
|
||||
import com.stevesoltys.seedvault.getRandomString
|
||||
import com.stevesoltys.seedvault.plugins.webdav.WebDavTestConfig
|
||||
import com.stevesoltys.seedvault.transport.backup.BackupTest
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.calyxos.backup.storage.api.StoredSnapshot
|
||||
import org.junit.Assert.assertArrayEquals
|
||||
|
@ -21,8 +19,7 @@ import java.io.IOException
|
|||
|
||||
internal class WebDavStoragePluginTest : BackupTest() {
|
||||
|
||||
private val keyManager: KeyManager = mockk()
|
||||
private val plugin = WebDavStoragePlugin(keyManager, "foo", WebDavTestConfig.getConfig())
|
||||
private val plugin = WebDavStoragePlugin("foo", WebDavTestConfig.getConfig())
|
||||
|
||||
private val snapshot = StoredSnapshot("foo.sv", System.currentTimeMillis())
|
||||
|
||||
|
@ -85,7 +82,7 @@ internal class WebDavStoragePluginTest : BackupTest() {
|
|||
)
|
||||
|
||||
// other device writes another snapshot
|
||||
val otherPlugin = WebDavStoragePlugin(keyManager, "bar", WebDavTestConfig.getConfig())
|
||||
val otherPlugin = WebDavStoragePlugin("bar", WebDavTestConfig.getConfig())
|
||||
val otherSnapshot = StoredSnapshot("bar.sv", System.currentTimeMillis())
|
||||
val otherSnapshotBytes = getRandomByteArray()
|
||||
assertEquals(emptyList<String>(), otherPlugin.getAvailableChunkIds())
|
||||
|
@ -110,7 +107,6 @@ internal class WebDavStoragePluginTest : BackupTest() {
|
|||
@Test
|
||||
fun `test missing root dir`() = runBlocking {
|
||||
val plugin = WebDavStoragePlugin(
|
||||
keyManager = keyManager,
|
||||
androidId = "foo",
|
||||
webDavConfig = WebDavTestConfig.getConfig(),
|
||||
root = getRandomString(),
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 The Calyx Institute
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.calyxos.seedvault.core.crypto
|
||||
|
||||
import java.security.KeyStore
|
||||
import javax.crypto.SecretKey
|
||||
|
||||
public interface KeyManager {
|
||||
/**
|
||||
* Returns the main key, so it can be used for deriving sub-keys.
|
||||
*
|
||||
* Note that any attempt to export the key will return null or an empty [ByteArray],
|
||||
* because the key can not leave the [KeyStore]'s hardware security module.
|
||||
*/
|
||||
public fun getMainKey(): SecretKey
|
||||
}
|
|
@ -69,6 +69,7 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":core"))
|
||||
implementation(project(":storage:lib"))
|
||||
|
||||
implementation(libs.bundles.kotlin)
|
||||
|
|
|
@ -9,6 +9,7 @@ import android.app.Application
|
|||
import android.os.StrictMode
|
||||
import android.os.StrictMode.VmPolicy
|
||||
import android.util.Log
|
||||
import de.grobox.storagebackuptester.crypto.KeyManager
|
||||
import de.grobox.storagebackuptester.plugin.TestSafStoragePlugin
|
||||
import de.grobox.storagebackuptester.settings.SettingsManager
|
||||
import org.calyxos.backup.storage.api.StorageBackup
|
||||
|
@ -19,7 +20,7 @@ class App : Application() {
|
|||
val settingsManager: SettingsManager by lazy { SettingsManager(applicationContext) }
|
||||
val storageBackup: StorageBackup by lazy {
|
||||
val plugin = TestSafStoragePlugin(this) { settingsManager.getBackupLocation() }
|
||||
StorageBackup(this, { plugin })
|
||||
StorageBackup(this, { plugin }, KeyManager)
|
||||
}
|
||||
val fileSelectionManager: FileSelectionManager get() = FileSelectionManager()
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ class MainActivity : AppCompatActivity() {
|
|||
|
||||
KeyManager.storeMasterKey()
|
||||
|
||||
if (!KeyManager.hasMasterKey()) {
|
||||
if (!KeyManager.hasMainKey()) {
|
||||
Log.e("TEST", "storing new key")
|
||||
KeyManager.storeMasterKey()
|
||||
} else {
|
||||
|
|
|
@ -14,7 +14,7 @@ import java.security.KeyStore
|
|||
import javax.crypto.SecretKey
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
|
||||
object KeyManager {
|
||||
object KeyManager: org.calyxos.seedvault.core.crypto.KeyManager {
|
||||
|
||||
private const val KEY_SIZE = 256
|
||||
internal const val KEY_SIZE_BYTES = KEY_SIZE / 8
|
||||
|
@ -42,9 +42,9 @@ object KeyManager {
|
|||
keyStore.setEntry(KEY_ALIAS_MASTER, ksEntry, getKeyProtection())
|
||||
}
|
||||
|
||||
fun hasMasterKey(): Boolean = keyStore.containsAlias(KEY_ALIAS_MASTER)
|
||||
fun hasMainKey(): Boolean = keyStore.containsAlias(KEY_ALIAS_MASTER)
|
||||
|
||||
fun getMasterKey(): SecretKey {
|
||||
override fun getMainKey(): SecretKey {
|
||||
val ksEntry = keyStore.getEntry(KEY_ALIAS_MASTER, null) as KeyStore.SecretKeyEntry
|
||||
return ksEntry.secretKey
|
||||
}
|
||||
|
|
|
@ -8,13 +8,10 @@ package de.grobox.storagebackuptester.plugin
|
|||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import de.grobox.storagebackuptester.crypto.KeyManager
|
||||
import org.calyxos.backup.storage.plugin.saf.SafStoragePlugin
|
||||
import java.io.IOException
|
||||
import java.io.OutputStream
|
||||
import javax.crypto.SecretKey
|
||||
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
class TestSafStoragePlugin(
|
||||
appContext: Context,
|
||||
private val getLocationUri: () -> Uri?,
|
||||
|
@ -33,14 +30,6 @@ class TestSafStoragePlugin(
|
|||
}
|
||||
}
|
||||
|
||||
override fun getMasterKey(): SecretKey {
|
||||
return KeyManager.getMasterKey()
|
||||
}
|
||||
|
||||
override fun hasMasterKey(): Boolean {
|
||||
return KeyManager.hasMasterKey()
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override suspend fun getChunkOutputStream(chunkId: String): OutputStream {
|
||||
if (getLocationUri() == null) return nullStream
|
||||
|
|
|
@ -81,6 +81,7 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":core"))
|
||||
implementation(libs.bundles.kotlin)
|
||||
implementation(libs.androidx.core)
|
||||
implementation(libs.androidx.fragment)
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.calyxos.backup.storage.scanner.DocumentScanner
|
|||
import org.calyxos.backup.storage.scanner.FileScanner
|
||||
import org.calyxos.backup.storage.scanner.MediaScanner
|
||||
import org.calyxos.backup.storage.toStoredUri
|
||||
import org.calyxos.seedvault.core.crypto.KeyManager
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
|
@ -39,6 +40,7 @@ private const val TAG = "StorageBackup"
|
|||
public class StorageBackup(
|
||||
private val context: Context,
|
||||
private val pluginGetter: () -> StoragePlugin,
|
||||
private val keyManager: KeyManager,
|
||||
private val dispatcher: CoroutineDispatcher = Dispatchers.IO,
|
||||
) {
|
||||
|
||||
|
@ -54,13 +56,16 @@ public class StorageBackup(
|
|||
private val backup by lazy {
|
||||
val documentScanner = DocumentScanner(context)
|
||||
val fileScanner = FileScanner(uriStore, mediaScanner, documentScanner)
|
||||
Backup(context, db, fileScanner, pluginGetter, chunksCacheRepopulater)
|
||||
Backup(context, db, fileScanner, pluginGetter, keyManager, chunksCacheRepopulater)
|
||||
}
|
||||
private val restore by lazy {
|
||||
Restore(context, pluginGetter, snapshotRetriever, FileRestore(context, mediaScanner))
|
||||
val fileRestore = FileRestore(context, mediaScanner)
|
||||
Restore(context, pluginGetter, keyManager, snapshotRetriever, fileRestore)
|
||||
}
|
||||
private val retention = RetentionManager(context)
|
||||
private val pruner by lazy { Pruner(db, retention, pluginGetter, snapshotRetriever) }
|
||||
private val pruner by lazy {
|
||||
Pruner(db, retention, pluginGetter, keyManager, snapshotRetriever)
|
||||
}
|
||||
|
||||
private val backupRunning = AtomicBoolean(false)
|
||||
private val restoreRunning = AtomicBoolean(false)
|
||||
|
|
|
@ -8,8 +8,6 @@ package org.calyxos.backup.storage.api
|
|||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.security.KeyStore
|
||||
import javax.crypto.SecretKey
|
||||
|
||||
public interface StoragePlugin {
|
||||
|
||||
|
@ -28,16 +26,6 @@ public interface StoragePlugin {
|
|||
@Throws(IOException::class)
|
||||
public suspend fun getAvailableChunkIds(): List<String>
|
||||
|
||||
/**
|
||||
* Returns a [SecretKey] for HmacSHA256, ideally stored in the [KeyStore].
|
||||
*/
|
||||
public fun getMasterKey(): SecretKey
|
||||
|
||||
/**
|
||||
* Returns true if the key for [getMasterKey] exists, false otherwise.
|
||||
*/
|
||||
public fun hasMasterKey(): Boolean
|
||||
|
||||
@Throws(IOException::class)
|
||||
public suspend fun getChunkOutputStream(chunkId: String): OutputStream
|
||||
|
||||
|
@ -48,8 +36,7 @@ public interface StoragePlugin {
|
|||
|
||||
/**
|
||||
* Returns *all* [StoredSnapshot]s that are available on storage
|
||||
* independent of user ID and whether they can be decrypted
|
||||
* with the key returned by [getMasterKey].
|
||||
* independent of user ID and whether they can be decrypted with the main key.
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
public suspend fun getBackupSnapshotsForRestore(): List<StoredSnapshot>
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.calyxos.backup.storage.db.Db
|
|||
import org.calyxos.backup.storage.measure
|
||||
import org.calyxos.backup.storage.scanner.FileScanner
|
||||
import org.calyxos.backup.storage.scanner.FileScannerResult
|
||||
import org.calyxos.seedvault.core.crypto.KeyManager
|
||||
import java.io.IOException
|
||||
import java.security.GeneralSecurityException
|
||||
import kotlin.time.Duration
|
||||
|
@ -42,6 +43,7 @@ internal class Backup(
|
|||
private val db: Db,
|
||||
private val fileScanner: FileScanner,
|
||||
private val storagePluginGetter: () -> StoragePlugin,
|
||||
keyManager: KeyManager,
|
||||
private val cacheRepopulater: ChunksCacheRepopulater,
|
||||
chunkSizeMax: Int = CHUNK_SIZE_MAX,
|
||||
private val streamCrypto: StreamCrypto = StreamCrypto,
|
||||
|
@ -60,12 +62,12 @@ internal class Backup(
|
|||
private val chunksCache = db.getChunksCache()
|
||||
|
||||
private val mac = try {
|
||||
ChunkCrypto.getMac(ChunkCrypto.deriveChunkIdKey(storagePlugin.getMasterKey()))
|
||||
ChunkCrypto.getMac(ChunkCrypto.deriveChunkIdKey(keyManager.getMainKey()))
|
||||
} catch (e: GeneralSecurityException) {
|
||||
throw AssertionError(e)
|
||||
}
|
||||
private val streamKey = try {
|
||||
streamCrypto.deriveStreamKey(storagePlugin.getMasterKey())
|
||||
streamCrypto.deriveStreamKey(keyManager.getMainKey())
|
||||
} catch (e: GeneralSecurityException) {
|
||||
throw AssertionError(e)
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.calyxos.backup.storage.crypto.StreamCrypto
|
|||
import org.calyxos.backup.storage.db.Db
|
||||
import org.calyxos.backup.storage.measure
|
||||
import org.calyxos.backup.storage.plugin.SnapshotRetriever
|
||||
import org.calyxos.seedvault.core.crypto.KeyManager
|
||||
import java.io.IOException
|
||||
import java.security.GeneralSecurityException
|
||||
import kotlin.time.ExperimentalTime
|
||||
|
@ -23,6 +24,7 @@ internal class Pruner(
|
|||
private val db: Db,
|
||||
private val retentionManager: RetentionManager,
|
||||
private val storagePluginGetter: () -> StoragePlugin,
|
||||
keyManager: KeyManager,
|
||||
private val snapshotRetriever: SnapshotRetriever,
|
||||
streamCrypto: StreamCrypto = StreamCrypto,
|
||||
) {
|
||||
|
@ -30,7 +32,7 @@ internal class Pruner(
|
|||
private val storagePlugin get() = storagePluginGetter()
|
||||
private val chunksCache = db.getChunksCache()
|
||||
private val streamKey = try {
|
||||
streamCrypto.deriveStreamKey(storagePlugin.getMasterKey())
|
||||
streamCrypto.deriveStreamKey(keyManager.getMainKey())
|
||||
} catch (e: GeneralSecurityException) {
|
||||
throw AssertionError(e)
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.calyxos.backup.storage.backup.BackupSnapshot
|
|||
import org.calyxos.backup.storage.crypto.StreamCrypto
|
||||
import org.calyxos.backup.storage.measure
|
||||
import org.calyxos.backup.storage.plugin.SnapshotRetriever
|
||||
import org.calyxos.seedvault.core.crypto.KeyManager
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.security.GeneralSecurityException
|
||||
|
@ -28,6 +29,7 @@ private const val TAG = "Restore"
|
|||
internal class Restore(
|
||||
context: Context,
|
||||
private val storagePluginGetter: () -> StoragePlugin,
|
||||
private val keyManager: KeyManager,
|
||||
private val snapshotRetriever: SnapshotRetriever,
|
||||
fileRestore: FileRestore,
|
||||
streamCrypto: StreamCrypto = StreamCrypto,
|
||||
|
@ -39,7 +41,7 @@ internal class Restore(
|
|||
// so we need to get it lazily here to prevent crashes. We can still crash later,
|
||||
// if the plugin is not providing a key as it should when performing calls into this class.
|
||||
try {
|
||||
streamCrypto.deriveStreamKey(storagePlugin.getMasterKey())
|
||||
streamCrypto.deriveStreamKey(keyManager.getMainKey())
|
||||
} catch (e: GeneralSecurityException) {
|
||||
throw AssertionError(e)
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ import org.calyxos.backup.storage.restore.RestorableFile
|
|||
import org.calyxos.backup.storage.restore.Restore
|
||||
import org.calyxos.backup.storage.scanner.FileScanner
|
||||
import org.calyxos.backup.storage.scanner.FileScannerResult
|
||||
import org.calyxos.seedvault.core.crypto.KeyManager
|
||||
import org.junit.Assert.assertArrayEquals
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
|
@ -71,6 +72,7 @@ internal class BackupRestoreTest {
|
|||
|
||||
private val fileScanner: FileScanner = mockk()
|
||||
private val pluginGetter: () -> StoragePlugin = mockk()
|
||||
private val keyManager: KeyManager = mockk()
|
||||
private val plugin: StoragePlugin = mockk()
|
||||
private val fileRestore: FileRestore = mockk()
|
||||
private val snapshotRetriever = SnapshotRetriever(pluginGetter)
|
||||
|
@ -87,7 +89,7 @@ internal class BackupRestoreTest {
|
|||
every { pluginGetter() } returns plugin
|
||||
every { db.getFilesCache() } returns filesCache
|
||||
every { db.getChunksCache() } returns chunksCache
|
||||
every { plugin.getMasterKey() } returns SecretKeySpec(
|
||||
every { keyManager.getMainKey() } returns SecretKeySpec(
|
||||
"This is a backup key for testing".toByteArray(),
|
||||
0, KEY_SIZE_BYTES, ALGORITHM_HMAC
|
||||
)
|
||||
|
@ -95,11 +97,11 @@ internal class BackupRestoreTest {
|
|||
every { context.contentResolver } returns contentResolver
|
||||
}
|
||||
|
||||
private val restore = Restore(context, pluginGetter, snapshotRetriever, fileRestore)
|
||||
private val restore = Restore(context, pluginGetter, keyManager, snapshotRetriever, fileRestore)
|
||||
|
||||
@Test
|
||||
fun testZipAndSingleRandom(): Unit = runBlocking {
|
||||
val backup = Backup(context, db, fileScanner, pluginGetter, cacheRepopulater)
|
||||
val backup = Backup(context, db, fileScanner, pluginGetter, keyManager, cacheRepopulater)
|
||||
|
||||
val smallFileMBytes = Random.nextBytes(Random.nextInt(SMALL_FILE_SIZE_MAX))
|
||||
val smallFileM = getRandomMediaFile(smallFileMBytes.size)
|
||||
|
@ -236,7 +238,8 @@ internal class BackupRestoreTest {
|
|||
|
||||
@Test
|
||||
fun testMultiChunks(): Unit = runBlocking {
|
||||
val backup = Backup(context, db, fileScanner, pluginGetter, cacheRepopulater, 4)
|
||||
val backup =
|
||||
Backup(context, db, fileScanner, pluginGetter, keyManager, cacheRepopulater, 4)
|
||||
|
||||
val chunk1 = byteArrayOf(0x00, 0x01, 0x02, 0x03)
|
||||
val chunk2 = byteArrayOf(0x04, 0x05, 0x06, 0x07)
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.calyxos.backup.storage.db.Db
|
|||
import org.calyxos.backup.storage.getRandomString
|
||||
import org.calyxos.backup.storage.mockLog
|
||||
import org.calyxos.backup.storage.plugin.SnapshotRetriever
|
||||
import org.calyxos.seedvault.core.crypto.KeyManager
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
@ -37,6 +38,7 @@ internal class PrunerTest {
|
|||
private val db: Db = mockk()
|
||||
private val chunksCache: ChunksCache = mockk()
|
||||
private val pluginGetter: () -> StoragePlugin = mockk()
|
||||
private val keyManager: KeyManager = mockk()
|
||||
private val plugin: StoragePlugin = mockk()
|
||||
private val snapshotRetriever: SnapshotRetriever = mockk()
|
||||
private val retentionManager: RetentionManager = mockk()
|
||||
|
@ -48,11 +50,12 @@ internal class PrunerTest {
|
|||
mockLog(false)
|
||||
every { pluginGetter() } returns plugin
|
||||
every { db.getChunksCache() } returns chunksCache
|
||||
every { plugin.getMasterKey() } returns masterKey
|
||||
every { keyManager.getMainKey() } returns masterKey
|
||||
every { streamCrypto.deriveStreamKey(masterKey) } returns streamKey
|
||||
}
|
||||
|
||||
private val pruner = Pruner(db, retentionManager, pluginGetter, snapshotRetriever, streamCrypto)
|
||||
private val pruner =
|
||||
Pruner(db, retentionManager, pluginGetter, keyManager, snapshotRetriever, streamCrypto)
|
||||
|
||||
@Test
|
||||
fun test() = runBlocking {
|
||||
|
|
Loading…
Reference in a new issue