mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-24 22:45:19 +00:00
* Refactor BLE transport event handling * Make image output paths unique * Keep queued Nostr read receipts alive * Refine BLE ingress fanout * Rediscover BLE service after invalidation * Extract BLE notification retry buffer * Extract BLE inbound write buffer * Extract BLE fragment assembly buffer * Tidy secure log handling from device run * Allow self-authored RSR ingress replies * Harden read receipt queue test timing --------- Co-authored-by: jack <jackjackbits@users.noreply.github.com>
179 lines
6.3 KiB
Swift
179 lines
6.3 KiB
Swift
import Foundation
|
|
import Testing
|
|
import BitFoundation
|
|
@testable import bitchat
|
|
|
|
struct BLEIngressLinkRegistryTests {
|
|
@Test
|
|
func recordIfNewSuppressesDuplicateWithinLifetime() {
|
|
var registry = BLEIngressLinkRegistry()
|
|
let packet = makePacket(sender: PeerID(str: "1122334455667788"), timestamp: 1)
|
|
let peer = PeerID(str: "1122334455667788")
|
|
let now = Date()
|
|
|
|
let firstRecord = registry.recordIfNew(packet, link: .central("central-a"), peerID: peer, now: now, lifetime: 3.0)
|
|
let duplicateRecord = registry.recordIfNew(packet, link: .peripheral("peripheral-b"), peerID: peer, now: now.addingTimeInterval(1.0), lifetime: 3.0)
|
|
|
|
#expect(firstRecord)
|
|
#expect(!duplicateRecord)
|
|
#expect(registry.link(for: packet) == .central("central-a"))
|
|
#expect(registry.peerID(for: packet) == peer)
|
|
}
|
|
|
|
@Test
|
|
func recordIfNewAllowsExpiredDuplicateAndUpdatesLink() {
|
|
var registry = BLEIngressLinkRegistry()
|
|
let packet = makePacket(sender: PeerID(str: "1122334455667788"), timestamp: 1)
|
|
let peer = PeerID(str: "1122334455667788")
|
|
let now = Date()
|
|
|
|
let firstRecord = registry.recordIfNew(packet, link: .central("central-a"), peerID: peer, now: now, lifetime: 3.0)
|
|
let expiredRecord = registry.recordIfNew(packet, link: .peripheral("peripheral-b"), peerID: peer, now: now.addingTimeInterval(4.0), lifetime: 3.0)
|
|
|
|
#expect(firstRecord)
|
|
#expect(expiredRecord)
|
|
#expect(registry.link(for: packet) == .peripheral("peripheral-b"))
|
|
#expect(registry.peerID(for: packet) == peer)
|
|
}
|
|
|
|
@Test
|
|
func pruneRemovesExpiredIngressLinks() {
|
|
var registry = BLEIngressLinkRegistry()
|
|
let packet = makePacket(sender: PeerID(str: "1122334455667788"), timestamp: 1)
|
|
let peer = PeerID(str: "1122334455667788")
|
|
let now = Date()
|
|
|
|
let firstRecord = registry.recordIfNew(packet, link: .central("central-a"), peerID: peer, now: now, lifetime: 3.0)
|
|
#expect(firstRecord)
|
|
registry.prune(before: now.addingTimeInterval(4.0))
|
|
|
|
#expect(registry.isEmpty)
|
|
#expect(registry.link(for: packet) == nil)
|
|
#expect(registry.peerID(for: packet) == nil)
|
|
}
|
|
|
|
@Test
|
|
func packetContextRejectsSelfLoopback() {
|
|
let localPeer = PeerID(str: "1122334455667788")
|
|
let packet = makePacket(sender: localPeer, timestamp: 1)
|
|
|
|
let result = BLEIngressLinkRegistry.packetContext(
|
|
for: packet,
|
|
claimedSenderID: localPeer,
|
|
boundPeerID: nil,
|
|
localPeerID: localPeer,
|
|
directAnnounceTTL: 7
|
|
)
|
|
|
|
#expect(result == .failure(.selfLoopback(packetType: MessageType.message.rawValue)))
|
|
}
|
|
|
|
@Test
|
|
func packetContextAllowsRelayedSenderOnBoundLink() throws {
|
|
let localPeer = PeerID(str: "0011223344556677")
|
|
let boundPeer = PeerID(str: "1122334455667788")
|
|
let relayedSender = PeerID(str: "8899aabbccddeeff")
|
|
let packet = makePacket(sender: relayedSender, timestamp: 1)
|
|
|
|
let context = try #require(trySuccess(BLEIngressLinkRegistry.packetContext(
|
|
for: packet,
|
|
claimedSenderID: relayedSender,
|
|
boundPeerID: boundPeer,
|
|
localPeerID: localPeer,
|
|
directAnnounceTTL: 7
|
|
)))
|
|
|
|
#expect(context.receivedFromPeerID == boundPeer)
|
|
#expect(context.validationPeerID == relayedSender)
|
|
}
|
|
|
|
@Test
|
|
func packetContextRejectsDirectAnnounceMismatchOnBoundLink() {
|
|
let localPeer = PeerID(str: "0011223344556677")
|
|
let boundPeer = PeerID(str: "1122334455667788")
|
|
let claimedPeer = PeerID(str: "8899aabbccddeeff")
|
|
let packet = makeAnnouncePacket(sender: claimedPeer, ttl: 7)
|
|
|
|
let result = BLEIngressLinkRegistry.packetContext(
|
|
for: packet,
|
|
claimedSenderID: claimedPeer,
|
|
boundPeerID: boundPeer,
|
|
localPeerID: localPeer,
|
|
directAnnounceTTL: 7
|
|
)
|
|
|
|
#expect(result == .failure(.directSenderMismatch(boundPeerID: boundPeer, claimedSenderID: claimedPeer)))
|
|
}
|
|
|
|
@Test
|
|
func packetContextUsesBoundPeerForRSRValidation() throws {
|
|
let localPeer = PeerID(str: "0011223344556677")
|
|
let boundPeer = PeerID(str: "1122334455667788")
|
|
let relayedSender = PeerID(str: "8899aabbccddeeff")
|
|
var packet = makePacket(sender: relayedSender, timestamp: 1)
|
|
packet.isRSR = true
|
|
|
|
let context = try #require(trySuccess(BLEIngressLinkRegistry.packetContext(
|
|
for: packet,
|
|
claimedSenderID: relayedSender,
|
|
boundPeerID: boundPeer,
|
|
localPeerID: localPeer,
|
|
directAnnounceTTL: 7
|
|
)))
|
|
|
|
#expect(context.receivedFromPeerID == boundPeer)
|
|
#expect(context.validationPeerID == boundPeer)
|
|
}
|
|
|
|
@Test
|
|
func packetContextAllowsSelfAuthoredRSRWithTTLZeroFromBoundPeer() throws {
|
|
let localPeer = PeerID(str: "0011223344556677")
|
|
let boundPeer = PeerID(str: "1122334455667788")
|
|
var packet = makePacket(sender: localPeer, timestamp: 1)
|
|
packet.isRSR = true
|
|
packet.ttl = 0
|
|
|
|
let context = try #require(trySuccess(BLEIngressLinkRegistry.packetContext(
|
|
for: packet,
|
|
claimedSenderID: localPeer,
|
|
boundPeerID: boundPeer,
|
|
localPeerID: localPeer,
|
|
directAnnounceTTL: 7
|
|
)))
|
|
|
|
#expect(context.receivedFromPeerID == boundPeer)
|
|
#expect(context.validationPeerID == boundPeer)
|
|
}
|
|
}
|
|
|
|
private func makePacket(sender: PeerID, timestamp: UInt64) -> BitchatPacket {
|
|
BitchatPacket(
|
|
type: MessageType.message.rawValue,
|
|
senderID: Data(hexString: sender.id) ?? Data(),
|
|
recipientID: nil,
|
|
timestamp: timestamp,
|
|
payload: Data("hello".utf8),
|
|
signature: nil,
|
|
ttl: 3
|
|
)
|
|
}
|
|
|
|
private func makeAnnouncePacket(sender: PeerID, ttl: UInt8) -> BitchatPacket {
|
|
BitchatPacket(
|
|
type: MessageType.announce.rawValue,
|
|
senderID: Data(hexString: sender.id) ?? Data(),
|
|
recipientID: nil,
|
|
timestamp: 1,
|
|
payload: Data(),
|
|
signature: nil,
|
|
ttl: ttl
|
|
)
|
|
}
|
|
|
|
private func trySuccess(_ result: Result<BLEIngressPacketContext, BLEIngressRejection>) -> BLEIngressPacketContext? {
|
|
guard case .success(let context) = result else {
|
|
return nil
|
|
}
|
|
return context
|
|
}
|