mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-24 22:45:19 +00:00
Merge pull request #952 from permissionlesstech/fix/file-transfer-peerid-normalization
Fix asymmetric voice/media delivery in private chats
This commit is contained in:
@@ -728,7 +728,10 @@ final class BLEService: NSObject {
|
||||
SecureLogger.error("❌ Failed to encode file packet for private send", category: .session)
|
||||
return
|
||||
}
|
||||
guard let recipientData = Data(hexString: peerID.id) else {
|
||||
// Normalize to short form (SHA256-derived 16-hex) for wire protocol compatibility
|
||||
// This ensures 64-hex Noise keys are converted to the canonical routing format
|
||||
let targetID = peerID.toShort()
|
||||
guard let recipientData = Data(hexString: targetID.id) else {
|
||||
SecureLogger.error("❌ Invalid recipient peer ID for file transfer: \(peerID)", category: .session)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -426,4 +426,70 @@ struct PeerIDTests {
|
||||
#expect(!PeerID(str: "nostr:\(hex65)").isValid)
|
||||
#expect(!PeerID(str: "nostr_\(hex65)").isValid)
|
||||
}
|
||||
|
||||
// MARK: - File Transfer PeerID Normalization
|
||||
// These tests verify the fix for asymmetric voice/media delivery (BCH-01-XXX)
|
||||
// The bug occurred when selectedPrivateChatPeer was migrated to 64-hex stable key
|
||||
// but the receiver expected SHA256-derived 16-hex format
|
||||
|
||||
@Test func fileTransfer_toShortNormalizesNoiseKeyToFingerprint() {
|
||||
// Given: A 64-hex Noise public key (what selectedPrivateChatPeer becomes after session)
|
||||
let noiseKey = Data(repeating: 0xAB, count: 32)
|
||||
let stableKeyPeerID = PeerID(hexData: noiseKey) // 64-hex
|
||||
|
||||
// When: Convert to short form (what sendFilePrivate should do)
|
||||
let shortID = stableKeyPeerID.toShort()
|
||||
|
||||
// Then: Should be 16-hex SHA256 fingerprint (matching myPeerID format)
|
||||
let expected = noiseKey.sha256Fingerprint().prefix(16)
|
||||
#expect(shortID.id == String(expected))
|
||||
#expect(shortID.id.count == 16)
|
||||
}
|
||||
|
||||
@Test func fileTransfer_shortIDMatchesMyPeerIDFormat() {
|
||||
// Given: A receiver's myPeerID is SHA256-derived (from refreshPeerIdentity)
|
||||
let noiseKey = Data(repeating: 0xCD, count: 32)
|
||||
let myPeerID = PeerID(publicKey: noiseKey) // SHA256-derived 16-hex
|
||||
|
||||
// When: Sender uses toShort() on 64-hex stable key
|
||||
let senderStableKey = PeerID(hexData: noiseKey) // 64-hex
|
||||
let recipientData = Data(hexString: senderStableKey.toShort().id)!
|
||||
let receivedRecipientID = PeerID(hexData: recipientData)
|
||||
|
||||
// Then: Should match receiver's myPeerID (file transfer accepted)
|
||||
#expect(receivedRecipientID == myPeerID)
|
||||
}
|
||||
|
||||
@Test func fileTransfer_truncatedRawKeyDoesNotMatchMyPeerID() {
|
||||
// This test demonstrates the bug we fixed
|
||||
// When 64-hex was truncated to first 8 bytes instead of using SHA256 fingerprint
|
||||
|
||||
// Given: Receiver's myPeerID is SHA256-derived
|
||||
let noiseKey = Data(repeating: 0xEF, count: 32)
|
||||
let myPeerID = PeerID(publicKey: noiseKey) // SHA256-derived 16-hex
|
||||
|
||||
// When: Truncate raw key (the OLD buggy behavior)
|
||||
let truncatedRaw = noiseKey.prefix(8) // First 8 bytes of raw key
|
||||
let wrongRecipientID = PeerID(hexData: truncatedRaw)
|
||||
|
||||
// Then: Should NOT match (demonstrates why fix was needed)
|
||||
#expect(wrongRecipientID != myPeerID)
|
||||
}
|
||||
|
||||
@Test func fileTransfer_shortIDProducesCorrect8ByteRoutingData() {
|
||||
// Verify the wire format is correct (8 bytes for BinaryProtocol)
|
||||
let noiseKey = Data(repeating: 0x12, count: 32)
|
||||
let stableKeyPeerID = PeerID(hexData: noiseKey)
|
||||
let shortID = stableKeyPeerID.toShort()
|
||||
|
||||
// routingData should be 8 bytes (16 hex chars -> 8 bytes)
|
||||
let routingData = shortID.routingData
|
||||
#expect(routingData != nil)
|
||||
#expect(routingData?.count == 8)
|
||||
|
||||
// And it should match SHA256 fingerprint first 8 bytes
|
||||
let expectedFingerprint = noiseKey.sha256Fingerprint()
|
||||
let expectedFirst8 = Data(hexString: String(expectedFingerprint.prefix(16)))
|
||||
#expect(routingData == expectedFirst8)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user