mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 00:25:19 +00:00
refactor(hex+fingerprint): centralize SHA256 fingerprint helper; reuse PeerIDResolver in ID checks
- Move Data.sha256Fingerprint() to BinaryEncodingUtils for reuse; refactor NoiseEncryptionService to use it.\n- Replace manual short/full hex checks with PeerIDResolver in ChatViewModel, ContentView, and SecureIdentityStateManager.\n- Keep behavior identical; reduce ad-hoc string length/hex parsing.
This commit is contained in:
@@ -310,7 +310,7 @@ class SecureIdentityStateManager {
|
||||
func getCryptoIdentitiesByPeerIDPrefix(_ peerID: String) -> [CryptographicIdentity] {
|
||||
queue.sync {
|
||||
// Defensive: ensure hex and correct length
|
||||
guard peerID.count == 16, peerID.allSatisfy({ $0.isHexDigit }) else { return [] }
|
||||
guard PeerIDResolver.isShortID(peerID) else { return [] }
|
||||
return cryptographicIdentities.values.filter { $0.fingerprint.hasPrefix(peerID) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CryptoKit
|
||||
|
||||
// MARK: - Hex Encoding/Decoding
|
||||
|
||||
@@ -35,6 +36,16 @@ extension Data {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Fingerprint Helpers
|
||||
|
||||
extension Data {
|
||||
/// SHA-256 over data, hex-encoded (lowercase)
|
||||
func sha256Fingerprint() -> String {
|
||||
let hash = SHA256.hash(data: self)
|
||||
return hash.map { String(format: "%02x", $0) }.joined()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Binary Encoding Utilities
|
||||
|
||||
extension Data {
|
||||
@@ -220,4 +231,3 @@ extension Data {
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -548,8 +548,7 @@ class NoiseEncryptionService {
|
||||
}
|
||||
|
||||
private func calculateFingerprint(for publicKey: Curve25519.KeyAgreement.PublicKey) -> String {
|
||||
let hash = SHA256.hash(data: publicKey.rawRepresentation)
|
||||
return hash.map { String(format: "%02x", $0) }.joined()
|
||||
return publicKey.rawRepresentation.sha256Fingerprint()
|
||||
}
|
||||
|
||||
// MARK: - Session Maintenance
|
||||
|
||||
@@ -412,10 +412,4 @@ class UnifiedPeerService: ObservableObject, TransportPeerEventsDelegate {
|
||||
|
||||
// MARK: - Helper Extensions
|
||||
|
||||
extension Data {
|
||||
func sha256Fingerprint() -> String {
|
||||
// Implementation matches existing fingerprint generation in NoiseEncryptionService
|
||||
let hash = SHA256.hash(data: self)
|
||||
return hash.map { String(format: "%02x", $0) }.joined()
|
||||
}
|
||||
}
|
||||
// Moved sha256Fingerprint() to BinaryEncodingUtils for reuse
|
||||
|
||||
@@ -161,7 +161,7 @@ class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
}()
|
||||
let full = (nostrKeyMapping[spid] ?? bare).lowercased()
|
||||
return "nostr:" + full
|
||||
} else if spid.count == 16, let full = getNoiseKeyForShortID(spid)?.lowercased() {
|
||||
} else if PeerIDResolver.isShortID(spid), let full = getNoiseKeyForShortID(spid)?.lowercased() {
|
||||
return "noise:" + full
|
||||
} else {
|
||||
return "mesh:" + spid.lowercased()
|
||||
@@ -309,7 +309,7 @@ class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
func getNoiseKeyForShortID(_ shortPeerID: String) -> String? {
|
||||
if let mapped = shortIDToNoiseKey[shortPeerID] { return mapped }
|
||||
// Fallback: derive from active Noise session if available
|
||||
if shortPeerID.count == 16,
|
||||
if PeerIDResolver.isShortID(shortPeerID),
|
||||
let key = meshService.getNoiseService().getPeerPublicKeyData(shortPeerID) {
|
||||
let stable = key.hexEncodedString()
|
||||
shortIDToNoiseKey[shortPeerID] = stable
|
||||
@@ -970,7 +970,7 @@ class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
// Ephemeral peer IDs are 8 bytes = 16 hex characters
|
||||
// Noise public keys are 32 bytes = 64 hex characters
|
||||
|
||||
if peerID.count == 64, let noisePublicKey = Data(hexString: peerID) {
|
||||
if PeerIDResolver.isNoiseKeyHex(peerID), let noisePublicKey = Data(hexString: peerID) {
|
||||
// This is a stable Noise key hex (used in private chats)
|
||||
// Find the ephemeral peer ID for this Noise key
|
||||
let ephemeralPeerID = unifiedPeerService.peers.first { peer in
|
||||
@@ -1033,7 +1033,7 @@ class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
@MainActor
|
||||
func isFavorite(peerID: String) -> Bool {
|
||||
// Distinguish between ephemeral peer IDs (16 hex chars) and Noise public keys (64 hex chars)
|
||||
if peerID.count == 64, let noisePublicKey = Data(hexString: peerID) {
|
||||
if PeerIDResolver.isNoiseKeyHex(peerID), let noisePublicKey = Data(hexString: peerID) {
|
||||
// This is a Noise public key
|
||||
if let status = FavoritesPersistenceService.shared.getFavoriteStatus(for: noisePublicKey) {
|
||||
return status.isFavorite
|
||||
@@ -3965,7 +3965,7 @@ class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
|
||||
// Check if this might already be a nickname (not a hex peer ID)
|
||||
// Peer IDs are hex strings, so they only contain 0-9 and a-f
|
||||
let isHexID = peerID.allSatisfy { $0.isHexDigit }
|
||||
let isHexID = PeerIDResolver.isShortID(peerID) || PeerIDResolver.isNoiseKeyHex(peerID)
|
||||
if !isHexID {
|
||||
// If it's already a nickname, just return it
|
||||
return peerID
|
||||
@@ -4519,7 +4519,7 @@ class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
|
||||
// Don't remove stable Noise key hexes (64 char hex strings) that have messages
|
||||
// These are used for Nostr messages when peer is offline
|
||||
if staleID.count == 64, staleID.allSatisfy({ $0.isHexDigit }) {
|
||||
if PeerIDResolver.isNoiseKeyHex(staleID) {
|
||||
if let messages = privateChats[staleID], !messages.isEmpty {
|
||||
// Keep this ID - it's a stable key with messages
|
||||
continue
|
||||
@@ -5086,7 +5086,7 @@ class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
var noiseKey: Data? = nil
|
||||
|
||||
// First try as hex-encoded Noise key (64 chars)
|
||||
if peerID.count == 64 {
|
||||
if PeerIDResolver.isNoiseKeyHex(peerID) {
|
||||
noiseKey = Data(hexString: peerID)
|
||||
}
|
||||
|
||||
@@ -5484,7 +5484,7 @@ class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
|
||||
// IMPORTANT: Also consolidate messages from stable Noise key if this is an ephemeral peer
|
||||
// This ensures Nostr messages appear in BLE chats
|
||||
if peerID.count == 16 { // This is an ephemeral peer ID (8 bytes = 16 hex chars)
|
||||
if PeerIDResolver.isShortID(peerID) { // This is an ephemeral peer ID (8 bytes = 16 hex chars)
|
||||
if let peer = unifiedPeerService.getPeer(by: peerID) {
|
||||
let stableKeyHex = peer.noisePublicKey.hexEncodedString()
|
||||
|
||||
|
||||
@@ -1182,7 +1182,7 @@ struct ContentView: View {
|
||||
private func privateHeaderContent(for privatePeerID: String) -> some View {
|
||||
// Prefer short (mesh) ID whenever available for encryption/session status; keep stable key for display resolution only.
|
||||
let headerPeerID: String = {
|
||||
if privatePeerID.count == 64 {
|
||||
if PeerIDResolver.isNoiseKeyHex(privatePeerID) {
|
||||
// Map stable Noise key to short ID if we know it (even if not directly connected)
|
||||
if let short = viewModel.getShortIDForNoiseKey(privatePeerID) { return short }
|
||||
}
|
||||
@@ -1207,14 +1207,14 @@ struct ContentView: View {
|
||||
if let fav = FavoritesPersistenceService.shared.getFavoriteStatus(for: Data(hexString: headerPeerID) ?? Data()),
|
||||
!fav.peerNickname.isEmpty { return fav.peerNickname }
|
||||
// Fallback: resolve from persisted social identity via fingerprint mapping
|
||||
if headerPeerID.count == 16 {
|
||||
if PeerIDResolver.isShortID(headerPeerID) {
|
||||
let candidates = SecureIdentityStateManager.shared.getCryptoIdentitiesByPeerIDPrefix(headerPeerID)
|
||||
if let id = candidates.first,
|
||||
let social = SecureIdentityStateManager.shared.getSocialIdentity(for: id.fingerprint) {
|
||||
if let pet = social.localPetname, !pet.isEmpty { return pet }
|
||||
if !social.claimedNickname.isEmpty { return social.claimedNickname }
|
||||
}
|
||||
} else if headerPeerID.count == 64, let keyData = Data(hexString: headerPeerID) {
|
||||
} else if PeerIDResolver.isNoiseKeyHex(headerPeerID), let keyData = Data(hexString: headerPeerID) {
|
||||
let fp = keyData.sha256Fingerprint()
|
||||
if let social = SecureIdentityStateManager.shared.getSocialIdentity(for: fp) {
|
||||
if let pet = social.localPetname, !pet.isEmpty { return pet }
|
||||
@@ -1298,7 +1298,7 @@ struct ContentView: View {
|
||||
if !privatePeerID.hasPrefix("nostr_") {
|
||||
// Use short peer ID if available for encryption status (sessions keyed by short ID)
|
||||
let statusPeerID: String = {
|
||||
if privatePeerID.count == 64, let short = viewModel.getShortIDForNoiseKey(privatePeerID) {
|
||||
if PeerIDResolver.isNoiseKeyHex(privatePeerID), let short = viewModel.getShortIDForNoiseKey(privatePeerID) {
|
||||
return short
|
||||
}
|
||||
return headerPeerID
|
||||
|
||||
Reference in New Issue
Block a user