Discard private-media callbacks during panic

This commit is contained in:
jack
2026-07-25 23:00:28 +02:00
parent 47dcb7c1b6
commit 15d8194e28
2 changed files with 70 additions and 7 deletions
+5 -7
View File
@@ -744,9 +744,8 @@ final class BLEService: NSObject {
ingressLinks.removeAll()
recentTrafficTracker.removeAll()
scheduledRelays.cancelAll()
let policyCompletions = pendingPrivateMediaPolicyResolutions.values.flatMap {
Array($0.completions.values)
}
// These callbacks belong to pre-panic transfer state. Invoking
// them would let queued UI work recreate or resend wiped media.
pendingPrivateMediaPolicyResolutions.removeAll()
privateMediaSessionGenerations.removeAll()
authenticatedPeerStates.removeAll()
@@ -755,14 +754,13 @@ final class BLEService: NSObject {
authenticatedPeerStateSendProgress.removeAll()
// Let the post-panic identity publish its fresh bundle promptly.
lastPrekeyBundleSentAt = nil
return (transfers, policyCompletions)
return transfers
}
for entry in panicReset.0 {
for entry in panicReset {
entry.workItems.forEach { $0.cancel() }
TransferProgressManager.shared.cancel(id: entry.id)
}
completePrivateMediaPolicyResolution(panicReset.1, with: .blockedDowngrade)
bleQueue.sync {
pendingWriteBuffers.removeAll()
@@ -1262,7 +1260,7 @@ final class BLEService: NSObject {
with policy: PrivateMediaSendPolicy
) {
guard !completions.isEmpty else { return }
Task { @MainActor in
notifyUI {
completions.forEach { $0(policy) }
}
}
@@ -546,6 +546,71 @@ struct PrivateMediaEndToEndTests {
bob._test_onOutboundPacket = nil
}
@Test
func panicDropsPendingPrivateMediaPolicyCompletion() async throws {
let root = FileManager.default.temporaryDirectory
.appendingPathComponent(
"private-media-policy-panic-\(UUID().uuidString)",
isDirectory: true
)
defer { try? FileManager.default.removeItem(at: root) }
let alice = makeService(
baseDirectory: root.appendingPathComponent(
"alice",
isDirectory: true
)
)
let bob = makeService(
baseDirectory: root.appendingPathComponent(
"bob",
isDirectory: true
)
)
alice._test_seedConnectedPeer(
bob.myPeerID,
nickname: "Prerelease Bob",
capabilities: .privateMedia,
noisePublicKey: bob.noiseStaticPublicKeyData()
)
_ = try await establishSessionCapturingPeerState(
alice: alice,
bob: bob
)
#expect(
alice.privateMediaSendPolicy(to: bob.myPeerID)
== .awaitingCapabilityProof
)
let recorder = PrivateMediaPolicyRecorder()
alice.resolvePrivateMediaSendPolicy(to: bob.myPeerID) {
recorder.record($0)
}
let registered = await TestHelpers.waitUntil(
{
alice._test_hasPendingPrivateMediaPolicyResolution(
for: bob.myPeerID
)
},
timeout: TestConstants.longTimeout
)
#expect(registered)
alice.suspendForPanicReset()
alice.resetIdentityForPanic(
currentNickname: "anon",
restartServices: false
)
alice._test_forcePrivateMediaProofTimeout(for: bob.myPeerID)
await Task.yield()
#expect(recorder.snapshot() == nil)
#expect(
!alice._test_hasPendingPrivateMediaPolicyResolution(
for: bob.myPeerID
)
)
}
@Test
func queuedPrivatePayloadWaitsForProofNotHandshakeCompletion() async throws {
let root = FileManager.default.temporaryDirectory