mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 12:45:20 +00:00
* Extract BLE service policy helpers * Stabilize image media transfer test --------- Co-authored-by: jack <jackjackbits@users.noreply.github.com>
149 lines
5.1 KiB
Swift
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
|
|
}
|
|
}
|