mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 22:45:20 +00:00
Unified Peer validation
This commit is contained in:
@@ -10,10 +10,6 @@ import Foundation
|
||||
|
||||
struct Peer: Equatable, Hashable {
|
||||
let id: String
|
||||
|
||||
var isShort: Bool {
|
||||
id.count == 16 && Data(hexString: id) != nil
|
||||
}
|
||||
}
|
||||
|
||||
extension Peer {
|
||||
@@ -30,6 +26,44 @@ extension Peer {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Validation
|
||||
|
||||
extension Peer {
|
||||
private enum Constants {
|
||||
static let maxIDLength = 64
|
||||
static let hexIDLength = 16 // 8 bytes = 16 hex chars
|
||||
}
|
||||
|
||||
/// Validates a peer ID from any source (short 16-hex, full 64-hex, or internal alnum/-/_ up to 64)
|
||||
var isValid: Bool {
|
||||
// Accept short routing IDs (exact 16-hex) or Full Noise key hex (exact 64-hex)
|
||||
if isShort || isNoiseKeyHex {
|
||||
return true
|
||||
}
|
||||
|
||||
// If length equals short or full but isn't valid hex, reject
|
||||
if id.count == Constants.hexIDLength || id.count == Constants.maxIDLength {
|
||||
return false
|
||||
}
|
||||
|
||||
// Internal format: alphanumeric + dash/underscore up to 63 (not 16 or 64)
|
||||
let validCharset = CharacterSet.alphanumerics.union(CharacterSet(charactersIn: "-_"))
|
||||
return !id.isEmpty &&
|
||||
id.count < Constants.maxIDLength &&
|
||||
id.rangeOfCharacter(from: validCharset.inverted) == nil
|
||||
}
|
||||
|
||||
/// Short routing IDs (exact 16-hex)
|
||||
var isShort: Bool {
|
||||
id.count == Constants.hexIDLength && Data(hexString: id) != nil
|
||||
}
|
||||
|
||||
/// Full Noise key hex (exact 64-hex)
|
||||
var isNoiseKeyHex: Bool {
|
||||
id.count == Constants.maxIDLength && Data(hexString: id) != nil
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - ExpressibleByStringLiteral
|
||||
|
||||
extension Peer: ExpressibleByStringLiteral {
|
||||
|
||||
@@ -79,7 +79,7 @@ struct ReadReceipt: Codable {
|
||||
|
||||
guard let readerIDData = dataCopy.readFixedBytes(at: &offset, count: 8) else { return nil }
|
||||
let readerID = readerIDData.hexEncodedString()
|
||||
guard InputValidator.validatePeerID(readerID) else { return nil }
|
||||
guard Peer(str: readerID).isValid else { return nil }
|
||||
|
||||
guard let timestamp = dataCopy.readDate(at: &offset),
|
||||
InputValidator.validateTimestamp(timestamp),
|
||||
|
||||
@@ -53,11 +53,6 @@ struct NoiseSecurityValidator {
|
||||
static func validateHandshakeMessageSize(_ data: Data) -> Bool {
|
||||
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
|
||||
|
||||
@@ -394,7 +394,7 @@ final class NoiseEncryptionService {
|
||||
func initiateHandshake(with peerID: String) throws -> Data {
|
||||
|
||||
// Validate peer ID
|
||||
guard NoiseSecurityValidator.validatePeerID(peerID) else {
|
||||
guard Peer(str: peerID).isValid else {
|
||||
SecureLogger.warning(.authenticationFailed(peerID: peerID))
|
||||
throw NoiseSecurityError.invalidPeerID
|
||||
}
|
||||
@@ -417,7 +417,7 @@ final class NoiseEncryptionService {
|
||||
func processHandshakeMessage(from peerID: String, message: Data) throws -> Data? {
|
||||
|
||||
// Validate peer ID
|
||||
guard NoiseSecurityValidator.validatePeerID(peerID) else {
|
||||
guard Peer(str: peerID).isValid else {
|
||||
SecureLogger.warning(.authenticationFailed(peerID: peerID))
|
||||
throw NoiseSecurityError.invalidPeerID
|
||||
}
|
||||
|
||||
@@ -10,27 +10,6 @@ struct InputValidator {
|
||||
static let maxNicknameLength = 50
|
||||
static let maxMessageLength = 10_000
|
||||
static let maxReasonLength = 200
|
||||
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
|
||||
|
||||
@@ -8,13 +8,5 @@ struct PeerIDResolver {
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user