fix(core): harden protected identity startup

This commit is contained in:
2026-08-09 20:25:16 +02:00
parent 429987785e
commit eefedd0cb0
25 changed files with 1351 additions and 616 deletions

View File

@@ -0,0 +1,17 @@
package com.vnidrop.app.core
import android.content.Context
internal object AndroidCoreRuntime {
init {
System.loadLibrary("vnidrop")
}
external fun initialize(context: Context): Boolean
}
fun initializeAndroidCoreRuntime(context: Context) {
check(AndroidCoreRuntime.initialize(context.applicationContext)) {
"The protected VniDrop runtime could not initialize"
}
}

View File

@@ -31,10 +31,12 @@ import uniffi.vnidrop.TransferMetadata
import uniffi.vnidrop.TransferAccessMode
import uniffi.vnidrop.VnidropCore
import uniffi.vnidrop.clearInactiveTransferCache
import uniffi.vnidrop.defaultCoreLimits
import uniffi.vnidrop.defaultCoreNetworkConfig
class CoreRepository(
class CoreRepository internal constructor(
private val dispatcher: CoroutineDispatcher = Dispatchers.IO,
private val coreFactory: CoreFactory = ProtectedCoreFactory,
) : CoreGateway {
private val _state = MutableStateFlow(CoreState())
override val state: StateFlow<CoreState> = _state.asStateFlow()
@@ -79,7 +81,7 @@ class CoreRepository(
_state.update { it.copy(isInitialized = false, status = null) }
core = null
disposeCore(previousCore)
core = VnidropCore.initializeWithNetworkConfig(appDataDir, sink, relaySettings.toNative())
core = createCore(appDataDir, relaySettings)
currentAppDataDir = appDataDir
currentRelaySettings = relaySettings
refreshSnapshot(requireCore())
@@ -190,7 +192,7 @@ class CoreRepository(
try {
reclaimed = clearInactiveTransferCache(appDataDir)
} finally {
core = VnidropCore.initializeWithNetworkConfig(appDataDir, sink, relaySettings.toNative())
core = createCore(appDataDir, relaySettings)
refreshSnapshot(requireCore())
_state.update { it.copy(isInitialized = true) }
}
@@ -207,6 +209,9 @@ class CoreRepository(
}
}
private fun createCore(appDataDir: String, relaySettings: RelaySettings): VnidropCore =
coreFactory.create(appDataDir, sink, relaySettings)
override suspend fun receivedArtifacts(): Result<List<ReceivedArtifactModel>> = runCore { activeCore ->
activeCore.listReceivedArtifacts().map { artifact ->
ReceivedArtifactModel(
@@ -330,6 +335,23 @@ class CoreRepository(
}
}
internal fun interface CoreFactory {
fun create(appDataDir: String, eventSink: CoreEventSink, relaySettings: RelaySettings): VnidropCore
}
private object ProtectedCoreFactory : CoreFactory {
override fun create(
appDataDir: String,
eventSink: CoreEventSink,
relaySettings: RelaySettings,
): VnidropCore = VnidropCore.initializeWithExperimentalSavedDevices(
appDataDir,
eventSink,
defaultCoreLimits(),
relaySettings.toNative(),
)
}
private fun RelaySettings.toNative(): CoreNetworkConfig = when (mode) {
RelayMode.Automatic -> defaultCoreNetworkConfig()
RelayMode.StrictCustom -> CoreNetworkConfig(

View File

@@ -6,13 +6,24 @@ import kotlinx.coroutines.test.runTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import uniffi.vnidrop.CoreNetworkConfig
import uniffi.vnidrop.CoreRelayMode
import uniffi.vnidrop.VnidropCore
class CoreRepositoryStorageTest {
@Test
fun cacheClearWaitsForActiveSharesThenRestartsWithTheSameIdentity() = runTest {
val appData = createTempDirectory("vnidrop-cache-clear")
val source = Files.write(appData.resolve("source.bin"), ByteArray(64 * 1024) { 5 })
val repository = CoreRepository()
val repository = CoreRepository(
coreFactory = CoreFactory { appDataDir, eventSink, _ ->
VnidropCore.initializeWithNetworkConfig(
appDataDir,
eventSink,
CoreNetworkConfig(CoreRelayMode.LOCAL_ONLY, emptyList()),
)
},
)
try {
assertTrue(
repository.initialize(