Files
bitchat/bitchatTests/Services/BLEIngressPacketGuardTests.swift
T
193cfdc06a [codex] Extract BLE service policy helpers (#1321)
* Extract BLE service policy helpers

* Stabilize image media transfer test

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2026-06-01 14:16:44 +02:00

149 lines
5.1 KiB
Swift

import BitFoundation
import Foundation
import Testing
@testable import bitchat
@Suite("BLE ingress packet guard tests")
struct BLEIngressPacketGuardTests {
@Test("valid packets return the received and validation peer context")
func validPacketsReturnContext() throws {
let local = PeerID(str: "0011223344556677")
let bound = PeerID(str: "1122334455667788")
let sender = PeerID(str: "8899aabbccddeeff")
let packet = makePacket(sender: sender, timestamp: 1_000)
let context = try #require(success(BLEIngressPacketGuard.evaluate(
packet: packet,
claimedSenderID: sender,
boundPeerID: bound,
localPeerID: local,
directAnnounceTTL: 7,
nowMs: 1_000,
isValidSyncResponse: { _ in false }
)))
#expect(context.receivedFromPeerID == bound)
#expect(context.validationPeerID == sender)
}
@Test("self loopback and direct announce spoofing are rejected before timestamp checks")
func linkBindingRejectionsWinBeforeTimestampChecks() {
let local = PeerID(str: "0011223344556677")
let bound = PeerID(str: "1122334455667788")
let claimed = PeerID(str: "8899aabbccddeeff")
let selfPacket = makePacket(sender: local, timestamp: 0)
let spoofedAnnounce = makePacket(type: .announce, sender: claimed, timestamp: 0, ttl: 7)
let selfResult = BLEIngressPacketGuard.evaluate(
packet: selfPacket,
claimedSenderID: local,
boundPeerID: bound,
localPeerID: local,
directAnnounceTTL: 7,
nowMs: 1_000_000,
isValidSyncResponse: { _ in false }
)
let spoofResult = BLEIngressPacketGuard.evaluate(
packet: spoofedAnnounce,
claimedSenderID: claimed,
boundPeerID: bound,
localPeerID: local,
directAnnounceTTL: 7,
nowMs: 1_000_000,
isValidSyncResponse: { _ in false }
)
#expect(selfResult == .failure(.selfLoopback(packetType: MessageType.message.rawValue)))
#expect(spoofResult == .failure(.directSenderMismatch(boundPeerID: bound, claimedSenderID: claimed)))
}
@Test("timestamp skew outside the window is rejected")
func timestampSkewIsRejected() {
let local = PeerID(str: "0011223344556677")
let sender = PeerID(str: "1122334455667788")
let packet = makePacket(sender: sender, timestamp: 1_000)
let result = BLEIngressPacketGuard.evaluate(
packet: packet,
claimedSenderID: sender,
boundPeerID: nil,
localPeerID: local,
directAnnounceTTL: 7,
nowMs: 200_000,
maxTimestampSkewMs: 120_000,
isValidSyncResponse: { _ in false }
)
#expect(result == .failure(.timestampSkew(
peerID: sender,
skewMs: 199_000,
maxSkewMs: 120_000
)))
}
@Test("valid RSR packets use bound peer validation and bypass timestamp skew")
func validRSRUsesBoundPeerAndBypassesTimestamp() throws {
let local = PeerID(str: "0011223344556677")
let bound = PeerID(str: "1122334455667788")
let sender = PeerID(str: "8899aabbccddeeff")
var packet = makePacket(sender: sender, timestamp: 1)
packet.isRSR = true
let context = try #require(success(BLEIngressPacketGuard.evaluate(
packet: packet,
claimedSenderID: sender,
boundPeerID: bound,
localPeerID: local,
directAnnounceTTL: 7,
nowMs: 1_000_000,
isValidSyncResponse: { $0 == bound }
)))
#expect(context.receivedFromPeerID == bound)
#expect(context.validationPeerID == bound)
}
@Test("invalid RSR packets are rejected")
func invalidRSRIsRejected() {
let local = PeerID(str: "0011223344556677")
let bound = PeerID(str: "1122334455667788")
let sender = PeerID(str: "8899aabbccddeeff")
var packet = makePacket(sender: sender, timestamp: 1)
packet.isRSR = true
let result = BLEIngressPacketGuard.evaluate(
packet: packet,
claimedSenderID: sender,
boundPeerID: bound,
localPeerID: local,
directAnnounceTTL: 7,
nowMs: 1_000_000,
isValidSyncResponse: { _ in false }
)
#expect(result == .failure(.invalidRSR(peerID: bound)))
}
private func makePacket(
type: MessageType = .message,
sender: PeerID,
timestamp: UInt64,
ttl: UInt8 = 3
) -> BitchatPacket {
BitchatPacket(
type: type.rawValue,
senderID: Data(hexString: sender.id) ?? Data(),
recipientID: nil,
timestamp: timestamp,
payload: Data([0x01, 0x02, 0x03]),
signature: nil,
ttl: ttl
)
}
private func success(_ result: Result<BLEIngressPacketContext, BLEIngressPacketGuard.Rejection>) -> BLEIngressPacketContext? {
guard case .success(let context) = result else { return nil }
return context
}
}