mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 03:45:20 +00:00
PeerID 31/n: Remove String interop to be explicit (#840)
* PeerID 28/n: `ChatViewModel.getShortIDForNoiseKey` * PeerID 29/n: `BLEService` + remove dupe funcs from #823 * `handleFileTransfer` to use PeerID * `sendMessage` and `sendPrivateMessage` * PeerID 30/n: Update some leftovers * `lowercased()` inside PeerID for normalization * PeerID 31/n: Remove String interop to be explicit * MockBLEService: Remove direct target delivery This causes a delivery even if the sender and receiver are not connected --------- Co-authored-by: jack <jackjackbits@users.noreply.github.com>
This commit is contained in:
@@ -246,7 +246,7 @@ final class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate {
|
|||||||
// Get peer ID from userInfo
|
// Get peer ID from userInfo
|
||||||
if let peerID = userInfo["peerID"] as? String {
|
if let peerID = userInfo["peerID"] as? String {
|
||||||
// Don't show notification if the private chat is already open
|
// Don't show notification if the private chat is already open
|
||||||
if chatViewModel?.selectedPrivateChatPeer == peerID {
|
if chatViewModel?.selectedPrivateChatPeer == PeerID(str: peerID) {
|
||||||
completionHandler([])
|
completionHandler([])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,12 @@ extension PeerID {
|
|||||||
init(hexData: Data) {
|
init(hexData: Data) {
|
||||||
self.init(str: hexData.hexEncodedString())
|
self.init(str: hexData.hexEncodedString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convenience init to "hide" hex-encoding implementation detail
|
||||||
|
init?(hexData: Data?) {
|
||||||
|
guard let hexData else { return nil }
|
||||||
|
self.init(hexData: hexData)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Noise Public Key Helpers
|
// MARK: - Noise Public Key Helpers
|
||||||
@@ -191,9 +197,7 @@ extension PeerID: Comparable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - String Interop Helpers
|
// MARK: - CustomStringConvertible
|
||||||
|
|
||||||
// MARK: CustomStringConvertible
|
|
||||||
|
|
||||||
extension PeerID: CustomStringConvertible {
|
extension PeerID: CustomStringConvertible {
|
||||||
/// So it returns the actual `id` like before even inside another String
|
/// So it returns the actual `id` like before even inside another String
|
||||||
@@ -201,17 +205,3 @@ extension PeerID: CustomStringConvertible {
|
|||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Custom Equatable w/ String & Optionality
|
|
||||||
|
|
||||||
// PeerID <> String
|
|
||||||
extension Optional where Wrapped == PeerID {
|
|
||||||
static func ==(lhs: Optional<Wrapped>, rhs: Optional<String>) -> Bool { lhs?.id == rhs }
|
|
||||||
static func !=(lhs: Optional<Wrapped>, rhs: Optional<String>) -> Bool { lhs?.id != rhs }
|
|
||||||
}
|
|
||||||
|
|
||||||
// String <> PeerID
|
|
||||||
extension Optional where Wrapped == String {
|
|
||||||
static func ==(lhs: Optional<Wrapped>, rhs: Optional<PeerID>) -> Bool { lhs == rhs?.id }
|
|
||||||
static func !=(lhs: Optional<Wrapped>, rhs: Optional<PeerID>) -> Bool { lhs != rhs?.id }
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -734,8 +734,7 @@ final class BLEService: NSObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func sendEncrypted(_ packet: BitchatPacket, data: Data, pad: Bool) {
|
private func sendEncrypted(_ packet: BitchatPacket, data: Data, pad: Bool) {
|
||||||
guard let recipientID = packet.recipientID else { return }
|
guard let recipientPeerID = PeerID(hexData: packet.recipientID) else { return }
|
||||||
let recipientPeerID = PeerID(hexData: recipientID)
|
|
||||||
var sentEncrypted = false
|
var sentEncrypted = false
|
||||||
|
|
||||||
// Per-link limits for the specific peer
|
// Per-link limits for the specific peer
|
||||||
@@ -1039,8 +1038,7 @@ final class BLEService: NSObject {
|
|||||||
|
|
||||||
// Skip directed packets that are not intended for us
|
// Skip directed packets that are not intended for us
|
||||||
if let recipient = packet.recipientID {
|
if let recipient = packet.recipientID {
|
||||||
let recipientHex = recipient.hexEncodedString()
|
if PeerID(hexData: recipient) != myPeerID && !recipient.allSatisfy({ $0 == 0xFF }) {
|
||||||
if recipientHex != myPeerID && !recipient.allSatisfy({ $0 == 0xFF }) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1122,10 +1120,7 @@ final class BLEService: NSObject {
|
|||||||
marker = "[file] \(fileName)"
|
marker = "[file] \(fileName)"
|
||||||
}
|
}
|
||||||
|
|
||||||
let isPrivateMessage: Bool = {
|
let isPrivateMessage = PeerID(hexData: packet.recipientID) == myPeerID
|
||||||
guard let recipient = packet.recipientID else { return false }
|
|
||||||
return recipient.hexEncodedString() == myPeerID
|
|
||||||
}()
|
|
||||||
|
|
||||||
if isPrivateMessage {
|
if isPrivateMessage {
|
||||||
updatePeerLastSeen(peerID)
|
updatePeerLastSeen(peerID)
|
||||||
@@ -3078,9 +3073,9 @@ extension BLEService {
|
|||||||
|
|
||||||
// Verify that the sender's derived ID from the announced noise public key matches the packet senderID
|
// Verify that the sender's derived ID from the announced noise public key matches the packet senderID
|
||||||
// This helps detect relayed or spoofed announces. Only warn in release; assert in debug.
|
// This helps detect relayed or spoofed announces. Only warn in release; assert in debug.
|
||||||
let derivedFromKey = PeerID(publicKey: announcement.noisePublicKey).id
|
let derivedFromKey = PeerID(publicKey: announcement.noisePublicKey)
|
||||||
if derivedFromKey != peerID {
|
if derivedFromKey != peerID {
|
||||||
SecureLogger.warning("⚠️ Announce sender mismatch: derived \(derivedFromKey.prefix(8))… vs packet \(peerID.id.prefix(8))…", category: .security)
|
SecureLogger.warning("⚠️ Announce sender mismatch: derived \(derivedFromKey.id.prefix(8))… vs packet \(peerID.id.prefix(8))…", category: .security)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3366,8 +3361,7 @@ extension BLEService {
|
|||||||
|
|
||||||
private func handleNoiseHandshake(_ packet: BitchatPacket, from peerID: PeerID) {
|
private func handleNoiseHandshake(_ packet: BitchatPacket, from peerID: PeerID) {
|
||||||
// Use NoiseEncryptionService for handshake processing
|
// Use NoiseEncryptionService for handshake processing
|
||||||
if let recipientID = packet.recipientID,
|
if PeerID(hexData: packet.recipientID) == myPeerID {
|
||||||
recipientID.hexEncodedString() == myPeerID {
|
|
||||||
// Handshake is for us
|
// Handshake is for us
|
||||||
do {
|
do {
|
||||||
if let response = try noiseService.processHandshakeMessage(from: peerID, message: packet.payload) {
|
if let response = try noiseService.processHandshakeMessage(from: peerID, message: packet.payload) {
|
||||||
@@ -3400,14 +3394,13 @@ extension BLEService {
|
|||||||
private func handleNoiseEncrypted(_ packet: BitchatPacket, from peerID: PeerID) {
|
private func handleNoiseEncrypted(_ packet: BitchatPacket, from peerID: PeerID) {
|
||||||
SecureLogger.debug("🔐 handleNoiseEncrypted called for packet from \(peerID)")
|
SecureLogger.debug("🔐 handleNoiseEncrypted called for packet from \(peerID)")
|
||||||
|
|
||||||
guard let recipientID = packet.recipientID else {
|
guard let recipientID = PeerID(hexData: packet.recipientID) else {
|
||||||
SecureLogger.warning("⚠️ Encrypted message has no recipient ID", category: .session)
|
SecureLogger.warning("⚠️ Encrypted message has no recipient ID", category: .session)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let recipientHex = recipientID.hexEncodedString()
|
if recipientID != myPeerID {
|
||||||
if recipientHex != myPeerID {
|
SecureLogger.debug("🔐 Encrypted message not for me (for \(recipientID), I am \(myPeerID))", category: .session)
|
||||||
SecureLogger.debug("🔐 Encrypted message not for me (for \(recipientHex), I am \(myPeerID))", category: .session)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
|
|||||||
nickname = trimmed
|
nickname = trimmed
|
||||||
}
|
}
|
||||||
// Update mesh service nickname if it's initialized
|
// Update mesh service nickname if it's initialized
|
||||||
if meshService.myPeerID != "" {
|
if !meshService.myPeerID.isEmpty {
|
||||||
meshService.setNickname(nickname)
|
meshService.setNickname(nickname)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4103,7 +4103,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
|
|||||||
if let spid = message.senderPeerID {
|
if let spid = message.senderPeerID {
|
||||||
if case .location(let ch) = activeChannel, spid.id.hasPrefix("nostr:") {
|
if case .location(let ch) = activeChannel, spid.id.hasPrefix("nostr:") {
|
||||||
if let myGeo = try? idBridge.deriveIdentity(forGeohash: ch.geohash) {
|
if let myGeo = try? idBridge.deriveIdentity(forGeohash: ch.geohash) {
|
||||||
return spid == "nostr:\(myGeo.publicKeyHex.prefix(TransportConfig.nostrShortKeyDisplayLength))"
|
return spid == PeerID(nostr: myGeo.publicKeyHex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return spid == meshService.myPeerID
|
return spid == meshService.myPeerID
|
||||||
@@ -5623,7 +5623,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate recipient
|
// Validate recipient
|
||||||
if let rid = packet.recipientID, rid.hexEncodedString() != meshService.myPeerID {
|
if PeerID(hexData: packet.recipientID) != meshService.myPeerID {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -186,11 +186,11 @@ struct PrivateChatE2ETests {
|
|||||||
// Bob relays private messages for Charlie
|
// Bob relays private messages for Charlie
|
||||||
bob.packetDeliveryHandler = { packet in
|
bob.packetDeliveryHandler = { packet in
|
||||||
if let recipientID = packet.recipientID,
|
if let recipientID = packet.recipientID,
|
||||||
String(data: recipientID, encoding: .utf8) == charlie.peerID {
|
PeerID(data: recipientID) == charlie.peerID {
|
||||||
// Relay to Charlie
|
// Relay to Charlie
|
||||||
var relayPacket = packet
|
var relayPacket = packet
|
||||||
relayPacket.ttl = packet.ttl - 1
|
relayPacket.ttl = packet.ttl - 1
|
||||||
self.charlie.simulateIncomingPacket(relayPacket)
|
charlie.simulateIncomingPacket(relayPacket)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -388,7 +388,7 @@ struct PublicChatE2ETests {
|
|||||||
|
|
||||||
if let message = BitchatMessage(packet.payload) {
|
if let message = BitchatMessage(packet.payload) {
|
||||||
// Don't relay own messages
|
// Don't relay own messages
|
||||||
guard message.senderPeerID?.id != node.peerID else { return }
|
guard message.senderPeerID != node.peerID else { return }
|
||||||
|
|
||||||
// Create relay message
|
// Create relay message
|
||||||
let relayMessage = BitchatMessage(
|
let relayMessage = BitchatMessage(
|
||||||
|
|||||||
@@ -203,10 +203,7 @@ final class MockBLEService: NSObject {
|
|||||||
let target = bus.service(for: recipientPeerID) {
|
let target = bus.service(for: recipientPeerID) {
|
||||||
target.simulateIncomingPacket(packet)
|
target.simulateIncomingPacket(packet)
|
||||||
} else {
|
} else {
|
||||||
// Not directly connected: deliver to neighbors for relay; also deliver directly if target is known
|
// Not directly connected: deliver to neighbors for relay
|
||||||
if let target = bus.service(for: recipientPeerID) {
|
|
||||||
target.simulateIncomingPacket(packet)
|
|
||||||
}
|
|
||||||
for neighbor in neighbors() where neighbor.peerID != recipientPeerID {
|
for neighbor in neighbors() where neighbor.peerID != recipientPeerID {
|
||||||
neighbor.simulateIncomingPacket(packet)
|
neighbor.simulateIncomingPacket(packet)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -273,7 +273,7 @@ struct PeerIDTests {
|
|||||||
@Test func comparable_sorting_and_equality() {
|
@Test func comparable_sorting_and_equality() {
|
||||||
let p1 = PeerID(str: "aaa")
|
let p1 = PeerID(str: "aaa")
|
||||||
let p2 = PeerID(str: "bbb")
|
let p2 = PeerID(str: "bbb")
|
||||||
let p3 = PeerID(str: "bbb")
|
let p3 = PeerID(str: "BBB")
|
||||||
|
|
||||||
#expect(p1 < p2)
|
#expect(p1 < p2)
|
||||||
#expect(p2 >= p1)
|
#expect(p2 >= p1)
|
||||||
@@ -284,44 +284,18 @@ struct PeerIDTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test func equality() {
|
@Test func equality() {
|
||||||
let string = "aaa"
|
let peerID = PeerID(str: "aaa")
|
||||||
let peerID = PeerID(str: string)
|
|
||||||
let badString = "bbb"
|
|
||||||
|
|
||||||
// PeerID == String
|
|
||||||
#expect(peerID == string)
|
|
||||||
#expect(peerID == Optional(string))
|
|
||||||
#expect(Optional(peerID) == string)
|
|
||||||
#expect(Optional(peerID) == Optional(string))
|
|
||||||
|
|
||||||
// PeerID != String
|
|
||||||
#expect(peerID != badString)
|
|
||||||
#expect(peerID != Optional(badString))
|
|
||||||
#expect(Optional(peerID) != badString)
|
|
||||||
#expect(Optional(peerID) != Optional(badString))
|
|
||||||
|
|
||||||
// String == PeerID
|
|
||||||
#expect(string == peerID)
|
|
||||||
#expect(Optional(string) == peerID)
|
|
||||||
#expect(string == Optional(peerID))
|
|
||||||
#expect(Optional(string) == Optional(peerID))
|
|
||||||
|
|
||||||
// String != PeerID
|
|
||||||
#expect(badString != peerID)
|
|
||||||
#expect(Optional(badString) != peerID)
|
|
||||||
#expect(badString != Optional(peerID))
|
|
||||||
#expect(Optional(badString) != Optional(peerID))
|
|
||||||
|
|
||||||
// Regular PeerID <> PeerID
|
// Regular PeerID <> PeerID
|
||||||
#expect(peerID == PeerID(str: "aaa"))
|
#expect(peerID == PeerID(str: "AAA"))
|
||||||
#expect(peerID == Optional(PeerID(str: "aaa")))
|
#expect(peerID == Optional(PeerID(str: "AAA")))
|
||||||
#expect(PeerID(str: "aaa") == peerID)
|
#expect(PeerID(str: "AAA") == peerID)
|
||||||
#expect(Optional(PeerID(str: "aaa")) == Optional(peerID))
|
#expect(Optional(PeerID(str: "AAA")) == Optional(peerID))
|
||||||
|
|
||||||
#expect(peerID != PeerID(str: "bbb"))
|
#expect(peerID != PeerID(str: "BBB"))
|
||||||
#expect(peerID != Optional(PeerID(str: "bbb")))
|
#expect(peerID != Optional(PeerID(str: "BBB")))
|
||||||
#expect(PeerID(str: "bbb") != peerID)
|
#expect(PeerID(str: "BBB") != peerID)
|
||||||
#expect(Optional(PeerID(str: "bbb")) != Optional(peerID))
|
#expect(Optional(PeerID(str: "BBB")) != Optional(peerID))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Computed properties
|
// MARK: - Computed properties
|
||||||
|
|||||||
Reference in New Issue
Block a user