diff --git a/bitchat/ViewModels/ChatViewModel.swift b/bitchat/ViewModels/ChatViewModel.swift index d695c50a..65760e87 100644 --- a/bitchat/ViewModels/ChatViewModel.swift +++ b/bitchat/ViewModels/ChatViewModel.swift @@ -171,7 +171,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate { if spid.isGeoChat || spid.isGeoDM { let full = (nostrKeyMapping[spid] ?? spid.bare).lowercased() return "nostr:" + full - } else if spid.id.count == 16, let full = getNoiseKeyForShortID(spid)?.lowercased() { + } else if spid.id.count == 16, let full = getNoiseKeyForShortID(spid)?.id.lowercased() { return "noise:" + full } else { return "mesh:" + spid.id.lowercased() @@ -328,16 +328,16 @@ final class ChatViewModel: ObservableObject, BitchatDelegate { private var peerIDToPublicKeyFingerprint: [PeerID: String] = [:] private var selectedPrivateChatFingerprint: String? = nil // Map stable short peer IDs (16-hex) to full Noise public key hex (64-hex) for session continuity - private var shortIDToNoiseKey: [PeerID: String] = [:] + private var shortIDToNoiseKey: [PeerID: PeerID] = [:] // Resolve full Noise key for a peer's short ID (used by UI header rendering) @MainActor - private func getNoiseKeyForShortID(_ shortPeerID: PeerID) -> String? { + private func getNoiseKeyForShortID(_ shortPeerID: PeerID) -> PeerID? { if let mapped = shortIDToNoiseKey[shortPeerID] { return mapped } // Fallback: derive from active Noise session if available if shortPeerID.id.count == 16, let key = meshService.getNoiseService().getPeerPublicKeyData(shortPeerID) { - let stable = key.hexEncodedString() + let stable = PeerID(hexData: key) shortIDToNoiseKey[shortPeerID] = stable return stable } @@ -346,16 +346,17 @@ final class ChatViewModel: ObservableObject, BitchatDelegate { // Resolve short mesh ID (16-hex) from a full Noise public key hex (64-hex) @MainActor - func getShortIDForNoiseKey(_ fullNoiseKeyHex: String) -> PeerID? { + func getShortIDForNoiseKey(_ fullNoiseKeyHex: PeerID) -> PeerID { + guard fullNoiseKeyHex.id.count == 64 else { return fullNoiseKeyHex } // Check known peers for a noise key match - if let match = allPeers.first(where: { $0.noisePublicKey.hexEncodedString() == fullNoiseKeyHex }) { + if let match = allPeers.first(where: { PeerID(hexData: $0.noisePublicKey) == fullNoiseKeyHex }) { return match.peerID } // Also search cache mapping if let pair = shortIDToNoiseKey.first(where: { $0.value == fullNoiseKeyHex }) { return pair.key } - return nil + return fullNoiseKeyHex } private var peerIndex: [PeerID: BitchatPeer] = [:] @@ -4423,7 +4424,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate { @MainActor private func meshSeed(for peerID: PeerID) -> String { - if let full = getNoiseKeyForShortID(peerID)?.lowercased() { + if let full = getNoiseKeyForShortID(peerID)?.id.lowercased() { return "noise:" + full } return peerID.id.lowercased() @@ -4899,9 +4900,9 @@ final class ChatViewModel: ObservableObject, BitchatDelegate { // Cache shortID -> full Noise key mapping as soon as session authenticates if self.shortIDToNoiseKey[peerID] == nil, let keyData = self.meshService.getNoiseService().getPeerPublicKeyData(peerID) { - let stable = keyData.hexEncodedString() + let stable = PeerID(hexData: keyData) self.shortIDToNoiseKey[peerID] = stable - SecureLogger.debug("🗺️ Mapped short peerID to Noise key for header continuity: \(peerID) -> \(stable.prefix(8))…", category: .session) + SecureLogger.debug("🗺️ Mapped short peerID to Noise key for header continuity: \(peerID) -> \(stable.id.prefix(8))…", category: .session) } // If a QR verification is pending but not sent yet, send it now that session is authenticated @@ -5166,7 +5167,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate { // Cache mapping to full Noise key for session continuity on disconnect if let peer = unifiedPeerService.getPeer(by: peerID) { - let noiseKeyHex = peer.noisePublicKey.hexEncodedString() + let noiseKeyHex = PeerID(hexData: peer.noisePublicKey) shortIDToNoiseKey[peerID] = noiseKeyHex } @@ -5182,15 +5183,14 @@ final class ChatViewModel: ObservableObject, BitchatDelegate { identityManager.removeEphemeralSession(peerID: peerID) // If the open PM is tied to this short peer ID, switch UI context to the full Noise key (offline favorite) - var derivedStableKeyHex: String? = shortIDToNoiseKey[peerID] + var derivedStableKeyHex = shortIDToNoiseKey[peerID] if derivedStableKeyHex == nil, let key = meshService.getNoiseService().getPeerPublicKeyData(peerID) { - derivedStableKeyHex = key.hexEncodedString() + derivedStableKeyHex = PeerID(hexData: key) shortIDToNoiseKey[peerID] = derivedStableKeyHex } - if let current = selectedPrivateChatPeer, current == peerID, - let stableKeyHex = PeerID(str: derivedStableKeyHex) { + if let current = selectedPrivateChatPeer, current == peerID, let stableKeyHex = derivedStableKeyHex { // Migrate messages view context to stable key so header shows favorite + Nostr globe if let messages = privateChats[peerID] { if privateChats[stableKeyHex] == nil { privateChats[stableKeyHex] = [] } diff --git a/bitchat/Views/ContentView.swift b/bitchat/Views/ContentView.swift index 6d37bec1..250e41fe 100644 --- a/bitchat/Views/ContentView.swift +++ b/bitchat/Views/ContentView.swift @@ -1213,12 +1213,7 @@ struct ContentView: View { .foregroundColor(textColor) if !privatePeerID.isGeoDM { - let statusPeerID: PeerID = { - if privatePeerID.id.count == 64, let short = viewModel.getShortIDForNoiseKey(privatePeerID.id) { - return short - } - return context.headerPeerID - }() + let statusPeerID = viewModel.getShortIDForNoiseKey(privatePeerID) let encryptionStatus = viewModel.getEncryptionStatus(for: statusPeerID) if let icon = encryptionStatus.icon { Image(systemName: icon) @@ -1252,13 +1247,7 @@ struct ContentView: View { } private func makePrivateHeaderContext(for privatePeerID: PeerID) -> PrivateHeaderContext { - let headerPeerID: PeerID = { - if privatePeerID.id.count == 64, let short = viewModel.getShortIDForNoiseKey(privatePeerID.id) { - return short - } - return privatePeerID - }() - + let headerPeerID = viewModel.getShortIDForNoiseKey(privatePeerID) let peer = viewModel.getPeer(byID: headerPeerID) let displayName: String = { diff --git a/bitchat/Views/FingerprintView.swift b/bitchat/Views/FingerprintView.swift index 51555d77..fc099a16 100644 --- a/bitchat/Views/FingerprintView.swift +++ b/bitchat/Views/FingerprintView.swift @@ -65,10 +65,7 @@ struct FingerprintView: View { VStack(alignment: .leading, spacing: 16) { // Prefer short mesh ID for session/encryption status - let statusPeerID: PeerID = { - if peerID.id.count == 64, let short = viewModel.getShortIDForNoiseKey(peerID.id) { return short } - return peerID - }() + let statusPeerID = viewModel.getShortIDForNoiseKey(peerID) // Resolve a friendly name let peerNickname: String = { if let p = viewModel.getPeer(byID: statusPeerID) { return p.displayName }