mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 06:05:20 +00:00
PeerID 6/n: Unifiy validation (#743)
This commit is contained in:
@@ -79,7 +79,7 @@ struct ReadReceipt: Codable {
|
|||||||
|
|
||||||
guard let readerIDData = dataCopy.readFixedBytes(at: &offset, count: 8) else { return nil }
|
guard let readerIDData = dataCopy.readFixedBytes(at: &offset, count: 8) else { return nil }
|
||||||
let readerID = readerIDData.hexEncodedString()
|
let readerID = readerIDData.hexEncodedString()
|
||||||
guard InputValidator.validatePeerID(readerID) else { return nil }
|
guard PeerID(str: readerID).isValid else { return nil }
|
||||||
|
|
||||||
guard let timestamp = dataCopy.readDate(at: &offset),
|
guard let timestamp = dataCopy.readDate(at: &offset),
|
||||||
InputValidator.validateTimestamp(timestamp),
|
InputValidator.validateTimestamp(timestamp),
|
||||||
|
|||||||
@@ -52,11 +52,6 @@ struct NoiseSecurityValidator {
|
|||||||
static func validateHandshakeMessageSize(_ data: Data) -> Bool {
|
static func validateHandshakeMessageSize(_ data: Data) -> Bool {
|
||||||
return data.count <= NoiseSecurityConstants.maxHandshakeMessageSize
|
return data.count <= NoiseSecurityConstants.maxHandshakeMessageSize
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validate peer ID format using unified validator
|
|
||||||
static func validatePeerID(_ peerID: String) -> Bool {
|
|
||||||
return InputValidator.validatePeerID(peerID)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Enhanced Noise Session with Security
|
// MARK: - Enhanced Noise Session with Security
|
||||||
|
|||||||
@@ -407,7 +407,7 @@ final class NoiseEncryptionService {
|
|||||||
func initiateHandshake(with peerID: String) throws -> Data {
|
func initiateHandshake(with peerID: String) throws -> Data {
|
||||||
|
|
||||||
// Validate peer ID
|
// Validate peer ID
|
||||||
guard NoiseSecurityValidator.validatePeerID(peerID) else {
|
guard PeerID(str: peerID).isValid else {
|
||||||
SecureLogger.warning(.authenticationFailed(peerID: peerID))
|
SecureLogger.warning(.authenticationFailed(peerID: peerID))
|
||||||
throw NoiseSecurityError.invalidPeerID
|
throw NoiseSecurityError.invalidPeerID
|
||||||
}
|
}
|
||||||
@@ -430,7 +430,7 @@ final class NoiseEncryptionService {
|
|||||||
func processHandshakeMessage(from peerID: String, message: Data) throws -> Data? {
|
func processHandshakeMessage(from peerID: String, message: Data) throws -> Data? {
|
||||||
|
|
||||||
// Validate peer ID
|
// Validate peer ID
|
||||||
guard NoiseSecurityValidator.validatePeerID(peerID) else {
|
guard PeerID(str: peerID).isValid else {
|
||||||
SecureLogger.warning(.authenticationFailed(peerID: peerID))
|
SecureLogger.warning(.authenticationFailed(peerID: peerID))
|
||||||
throw NoiseSecurityError.invalidPeerID
|
throw NoiseSecurityError.invalidPeerID
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,27 +11,6 @@ struct InputValidator {
|
|||||||
// BinaryProtocol caps payload length at UInt16.max (65_535). Leave headroom
|
// BinaryProtocol caps payload length at UInt16.max (65_535). Leave headroom
|
||||||
// for headers/padding by limiting user content to 60_000 bytes.
|
// for headers/padding by limiting user content to 60_000 bytes.
|
||||||
static let maxMessageLength = 60_000
|
static let maxMessageLength = 60_000
|
||||||
static let maxPeerIDLength = 64
|
|
||||||
static let hexPeerIDLength = 16 // 8 bytes = 16 hex chars
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Peer ID Validation
|
|
||||||
|
|
||||||
/// Validates a peer ID from any source (short 16-hex, full 64-hex, or internal alnum/-/_ up to 64)
|
|
||||||
static func validatePeerID(_ peerID: String) -> Bool {
|
|
||||||
// Accept short routing IDs (exact 16-hex)
|
|
||||||
if PeerIDResolver.isShortID(peerID) { return true }
|
|
||||||
// If length equals short-hex length but isn't valid hex, reject
|
|
||||||
if peerID.count == Limits.hexPeerIDLength { return false }
|
|
||||||
// Accept full Noise key hex (exact 64-hex)
|
|
||||||
if PeerIDResolver.isNoiseKeyHex(peerID) { return true }
|
|
||||||
// If length equals full key length but isn't valid hex, reject
|
|
||||||
if peerID.count == Limits.maxPeerIDLength { return false }
|
|
||||||
// Internal format: alphanumeric + dash/underscore up to 63 (not 16 or 64)
|
|
||||||
let validCharset = CharacterSet.alphanumerics.union(CharacterSet(charactersIn: "-_"))
|
|
||||||
return !peerID.isEmpty &&
|
|
||||||
peerID.count < Limits.maxPeerIDLength &&
|
|
||||||
peerID.rangeOfCharacter(from: validCharset.inverted) == nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - String Content Validation
|
// MARK: - String Content Validation
|
||||||
|
|||||||
@@ -8,13 +8,5 @@ struct PeerIDResolver {
|
|||||||
}
|
}
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
static func isShortID(_ id: String) -> Bool {
|
|
||||||
return id.count == 16 && Data(hexString: id) != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
static func isNoiseKeyHex(_ id: String) -> Bool {
|
|
||||||
return id.count == 64 && Data(hexString: id) != nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
//
|
|
||||||
// InputValidatorTests.swift
|
|
||||||
// bitchatTests
|
|
||||||
//
|
|
||||||
// This is free and unencumbered software released into the public domain.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
@testable import bitchat
|
|
||||||
|
|
||||||
final class InputValidatorTests: XCTestCase {
|
|
||||||
func test_accepts_short_hex_peer_id() {
|
|
||||||
XCTAssertTrue(InputValidator.validatePeerID("0011223344556677"))
|
|
||||||
XCTAssertTrue(InputValidator.validatePeerID("aabbccddeeff0011"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func test_accepts_full_noise_key_hex() {
|
|
||||||
let hex64 = String(repeating: "ab", count: 32) // 64 hex chars
|
|
||||||
XCTAssertTrue(InputValidator.validatePeerID(hex64))
|
|
||||||
}
|
|
||||||
|
|
||||||
func test_accepts_internal_alnum_dash_underscore() {
|
|
||||||
XCTAssertTrue(InputValidator.validatePeerID("peer_123-ABC"))
|
|
||||||
XCTAssertTrue(InputValidator.validatePeerID("nostr_user_01"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func test_rejects_invalid_characters() {
|
|
||||||
XCTAssertFalse(InputValidator.validatePeerID("peer!@#"))
|
|
||||||
XCTAssertFalse(InputValidator.validatePeerID("gggggggggggggggg")) // not hex for short form
|
|
||||||
}
|
|
||||||
|
|
||||||
func test_rejects_too_long() {
|
|
||||||
let tooLong = String(repeating: "a", count: 65)
|
|
||||||
XCTAssertFalse(InputValidator.validatePeerID(tooLong))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user