From 524a7e916b449901c7a1c4567f676e6648191b94 Mon Sep 17 00:00:00 2001 From: Islam <2553451+qalandarov@users.noreply.github.com> Date: Fri, 3 Oct 2025 10:32:13 +0100 Subject: [PATCH] PeerID 8/n: NoiseRateLimiter & FavoritesPersistenceService (#745) --- bitchat/Noise/NoiseSecurityConsiderations.swift | 10 +++++----- bitchat/Services/FavoritesPersistenceService.swift | 6 +++--- bitchat/Services/MessageRouter.swift | 2 +- bitchat/Services/NoiseEncryptionService.swift | 8 ++++---- bitchat/Services/NostrTransport.swift | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/bitchat/Noise/NoiseSecurityConsiderations.swift b/bitchat/Noise/NoiseSecurityConsiderations.swift index 61a863c3..02245a5d 100644 --- a/bitchat/Noise/NoiseSecurityConsiderations.swift +++ b/bitchat/Noise/NoiseSecurityConsiderations.swift @@ -131,8 +131,8 @@ final class SecureNoiseSession: NoiseSession { // MARK: - Rate Limiter final class NoiseRateLimiter { - private var handshakeTimestamps: [String: [Date]] = [:] // peerID -> timestamps - private var messageTimestamps: [String: [Date]] = [:] // peerID -> timestamps + private var handshakeTimestamps: [PeerID: [Date]] = [:] + private var messageTimestamps: [PeerID: [Date]] = [:] // Global rate limiting private var globalHandshakeTimestamps: [Date] = [] @@ -140,7 +140,7 @@ final class NoiseRateLimiter { private let queue = DispatchQueue(label: "chat.bitchat.noise.ratelimit", attributes: .concurrent) - func allowHandshake(from peerID: String) -> Bool { + func allowHandshake(from peerID: PeerID) -> Bool { return queue.sync(flags: .barrier) { let now = Date() let oneMinuteAgo = now.addingTimeInterval(-60) @@ -169,7 +169,7 @@ final class NoiseRateLimiter { } } - func allowMessage(from peerID: String) -> Bool { + func allowMessage(from peerID: PeerID) -> Bool { return queue.sync(flags: .barrier) { let now = Date() let oneSecondAgo = now.addingTimeInterval(-1) @@ -198,7 +198,7 @@ final class NoiseRateLimiter { } } - func reset(for peerID: String) { + func reset(for peerID: PeerID) { queue.async(flags: .barrier) { self.handshakeTimestamps.removeValue(forKey: peerID) self.messageTimestamps.removeValue(forKey: peerID) diff --git a/bitchat/Services/FavoritesPersistenceService.swift b/bitchat/Services/FavoritesPersistenceService.swift index 3e38c297..fd71e4b7 100644 --- a/bitchat/Services/FavoritesPersistenceService.swift +++ b/bitchat/Services/FavoritesPersistenceService.swift @@ -179,10 +179,10 @@ final class FavoritesPersistenceService: ObservableObject { /// Resolve favorite status by short peer ID (16-hex derived from Noise pubkey) /// Falls back to scanning favorites and matching on derived peer ID. - func getFavoriteStatus(forPeerID peerID: String) -> FavoriteRelationship? { + func getFavoriteStatus(forPeerID peerID: PeerID) -> FavoriteRelationship? { // Quick sanity: peerID should be 16 hex chars (8 bytes) - guard peerID.count == 16 else { return nil } - for (pubkey, rel) in favorites where PeerID(publicKey: pubkey).id == peerID { + guard peerID.isShort else { return nil } + for (pubkey, rel) in favorites where PeerID(publicKey: pubkey) == peerID { return rel } return nil diff --git a/bitchat/Services/MessageRouter.swift b/bitchat/Services/MessageRouter.swift index 70c18c37..1b1b60d6 100644 --- a/bitchat/Services/MessageRouter.swift +++ b/bitchat/Services/MessageRouter.swift @@ -94,7 +94,7 @@ final class MessageRouter { return true } } else if peerID.count == 16 { - if let fav = FavoritesPersistenceService.shared.getFavoriteStatus(forPeerID: peerID), + if let fav = FavoritesPersistenceService.shared.getFavoriteStatus(forPeerID: PeerID(str: peerID)), fav.peerNostrPublicKey != nil { return true } diff --git a/bitchat/Services/NoiseEncryptionService.swift b/bitchat/Services/NoiseEncryptionService.swift index fa9f92e5..c406ff54 100644 --- a/bitchat/Services/NoiseEncryptionService.swift +++ b/bitchat/Services/NoiseEncryptionService.swift @@ -413,7 +413,7 @@ final class NoiseEncryptionService { } // Check rate limit - guard rateLimiter.allowHandshake(from: peerID) else { + guard rateLimiter.allowHandshake(from: PeerID(str: peerID)) else { SecureLogger.warning(.authenticationFailed(peerID: "Rate limited: \(peerID)")) throw NoiseSecurityError.rateLimitExceeded } @@ -442,7 +442,7 @@ final class NoiseEncryptionService { } // Check rate limit - guard rateLimiter.allowHandshake(from: peerID) else { + guard rateLimiter.allowHandshake(from: PeerID(str: peerID)) else { SecureLogger.warning(.authenticationFailed(peerID: "Rate limited: \(peerID)")) throw NoiseSecurityError.rateLimitExceeded } @@ -476,7 +476,7 @@ final class NoiseEncryptionService { } // Check rate limit - guard rateLimiter.allowMessage(from: peerID) else { + guard rateLimiter.allowMessage(from: PeerID(str: peerID)) else { throw NoiseSecurityError.rateLimitExceeded } @@ -498,7 +498,7 @@ final class NoiseEncryptionService { } // Check rate limit - guard rateLimiter.allowMessage(from: peerID) else { + guard rateLimiter.allowMessage(from: PeerID(str: peerID)) else { throw NoiseSecurityError.rateLimitExceeded } diff --git a/bitchat/Services/NostrTransport.swift b/bitchat/Services/NostrTransport.swift index 8aee7ab3..5989a28c 100644 --- a/bitchat/Services/NostrTransport.swift +++ b/bitchat/Services/NostrTransport.swift @@ -174,7 +174,7 @@ final class NostrTransport: Transport { return npub } if peerID.count == 16, - let fav = FavoritesPersistenceService.shared.getFavoriteStatus(forPeerID: peerID), + let fav = FavoritesPersistenceService.shared.getFavoriteStatus(forPeerID: PeerID(str: peerID)), let npub = fav.peerNostrPublicKey { return npub }