Trim whitespace from nicknames to prevent display issues

- Added didSet observer to nickname property to trim on every change
- Trim nickname when loading from UserDefaults
- Update validateAndSaveNickname to properly trim
- Trim received nicknames in announce packets
- Add custom init/decoder for NoiseIdentityAnnouncement to ensure trimming
- Trim nicknames when decoding from binary data
This commit is contained in:
jack
2025-07-25 20:29:50 +02:00
parent e57bfad843
commit 0e78341102
3 changed files with 41 additions and 7 deletions
+20 -2
View File
@@ -654,12 +654,27 @@ struct NoiseIdentityAnnouncement: Codable {
self.peerID = peerID
self.publicKey = publicKey
self.signingPublicKey = signingPublicKey
self.nickname = nickname
// Trim whitespace from nickname
self.nickname = nickname.trimmingCharacters(in: .whitespacesAndNewlines)
self.timestamp = timestamp
self.previousPeerID = previousPeerID
self.signature = signature
}
// Custom decoder to ensure nickname is trimmed
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.peerID = try container.decode(String.self, forKey: .peerID)
self.publicKey = try container.decode(Data.self, forKey: .publicKey)
self.signingPublicKey = try container.decode(Data.self, forKey: .signingPublicKey)
// Trim whitespace from decoded nickname
let rawNickname = try container.decode(String.self, forKey: .nickname)
self.nickname = rawNickname.trimmingCharacters(in: .whitespacesAndNewlines)
self.timestamp = try container.decode(Date.self, forKey: .timestamp)
self.previousPeerID = try container.decodeIfPresent(String.self, forKey: .previousPeerID)
self.signature = try container.decode(Data.self, forKey: .signature)
}
func encode() -> Data? {
return try? JSONEncoder().encode(self)
}
@@ -738,9 +753,12 @@ struct NoiseIdentityAnnouncement: Codable {
guard let publicKey = dataCopy.readData(at: &offset),
let signingPublicKey = dataCopy.readData(at: &offset),
let nickname = dataCopy.readString(at: &offset),
let rawNickname = dataCopy.readString(at: &offset),
let timestamp = dataCopy.readDate(at: &offset) else { return nil }
// Trim whitespace from nickname
let nickname = rawNickname.trimmingCharacters(in: .whitespacesAndNewlines)
var previousPeerID: String? = nil
if hasPreviousPeerID {
// Read previousPeerID using safe method
+3 -1
View File
@@ -2592,7 +2592,9 @@ class BluetoothMeshService: NSObject {
// Note: 0x02 was legacy keyExchange - removed
case .announce:
if let nickname = String(data: packet.payload, encoding: .utf8) {
if let rawNickname = String(data: packet.payload, encoding: .utf8) {
// Trim whitespace from received nickname
let nickname = rawNickname.trimmingCharacters(in: .whitespacesAndNewlines)
let senderID = packet.senderID.hexEncodedString()
SecureLogger.log("handleReceivedPacket: Received announce from \(senderID), peripheral is \(peripheral != nil ? "present" : "nil")", category: SecureLogger.session, level: .debug)
+18 -4
View File
@@ -25,7 +25,15 @@ class ChatViewModel: ObservableObject {
private var pendingPrivateMessages: [String: [BitchatMessage]] = [:] // peerID -> messages
private var messageBatchTimer: Timer?
private let messageBatchInterval: TimeInterval = 0.1 // 100ms batching window
@Published var nickname: String = ""
@Published var nickname: String = "" {
didSet {
// Trim whitespace whenever nickname is set
let trimmed = nickname.trimmingCharacters(in: .whitespacesAndNewlines)
if trimmed != nickname {
nickname = trimmed
}
}
}
@Published var isConnected = false
@Published var privateChats: [String: [BitchatMessage]] = [:] // peerID -> messages
@Published var selectedPrivateChatPeer: String? = nil
@@ -176,7 +184,8 @@ class ChatViewModel: ObservableObject {
private func loadNickname() {
if let savedNickname = userDefaults.string(forKey: nicknameKey) {
nickname = savedNickname
// Trim whitespace when loading
nickname = savedNickname.trimmingCharacters(in: .whitespacesAndNewlines)
} else {
nickname = "anon\(Int.random(in: 1000...9999))"
saveNickname()
@@ -192,9 +201,14 @@ class ChatViewModel: ObservableObject {
}
func validateAndSaveNickname() {
// Check if nickname is empty or just whitespace
if nickname.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
// Trim whitespace from nickname
let trimmed = nickname.trimmingCharacters(in: .whitespacesAndNewlines)
// Check if nickname is empty after trimming
if trimmed.isEmpty {
nickname = "anon\(Int.random(in: 1000...9999))"
} else {
nickname = trimmed
}
saveNickname()
}