Replace .log w/ explicit .debug/.error functions

This would make the intention more explicit so we can overload different logging types as well like keychain, security events, etc…

Search/Replace Strategies:

1.
Search regex: `SecureLogger\.log\(\s*(.*?),\s*category:\s*(.*?),\s*level:\s*\.(\w+)\s*\)`
Replace regex: `SecureLogger.$3($1, category: $2)`

Sample input:
```
SecureLogger.log(
    "🔄 Found favorite for '\(peerInfo.nickname)' by nickname, updating noise key",
    category: .session,
    level: .debug
)
```

Sample output:
`SecureLogger.debug("🔄 Found favorite for '\(peerInfo.nickname)' by nickname, updating noise key", category: .session)`

---

2.
Search regex: `SecureLogger\.log\((.*?)\)`
Replace regex: `SecureLogger.debug($1)` (as it’s the default level)

Sample input:
`SecureLogger.log("some text")`

Sample output:
`SecureLogger.debug("some text")`

---

3
Manual changes:
ChatViewModel line 5393 (commented code)
NostrRelayManager line 196 (commented code)
NostrRelayManager lines 346-350 (if/else logic)
NostrRelayManager line 371 (commented code)
This commit is contained in:
islam
2025-09-11 19:03:08 +01:00
parent 5ca9222fc2
commit 5d6aecfc83
20 changed files with 362 additions and 487 deletions
+94 -121
View File
@@ -230,8 +230,7 @@ final class BLEService: NSObject {
let newSize = data.count
// If single chunk exceeds cap, drop it immediately
if newSize > capBytes {
SecureLogger.log("⚠️ Dropping oversized write chunk (\(newSize)B) for peripheral \(uuid)",
category: .session, level: .warning)
SecureLogger.warning("⚠️ Dropping oversized write chunk (\(newSize)B) for peripheral \(uuid)", category: .session)
} else {
// Append and trim from the front to respect cap
var total = queue.reduce(0) { $0 + $1.count }
@@ -244,8 +243,7 @@ final class BLEService: NSObject {
removedBytes += removed.count
total -= removed.count
}
SecureLogger.log("📉 Trimmed pending write buffer for \(uuid) by \(removedBytes)B to \(total)B",
category: .session, level: .warning)
SecureLogger.warning("📉 Trimmed pending write buffer for \(uuid) by \(removedBytes)B to \(total)B", category: .session)
}
self.pendingPeripheralWrites[uuid] = queue.isEmpty ? nil : queue
}
@@ -341,8 +339,7 @@ final class BLEService: NSObject {
// Set up Noise session establishment callback
// This ensures we send pending messages only when session is truly established
noiseService.onPeerAuthenticated = { [weak self] peerID, fingerprint in
SecureLogger.log("🔐 Noise session authenticated with \(peerID), fingerprint: \(fingerprint.prefix(16))...",
category: .noise, level: .debug)
SecureLogger.debug("🔐 Noise session authenticated with \(peerID), fingerprint: \(fingerprint.prefix(16))...", category: .noise)
// Send any messages that were queued during handshake
self?.messageQueue.async { [weak self] in
self?.sendPendingMessagesAfterHandshake(for: peerID)
@@ -587,8 +584,7 @@ final class BLEService: NSObject {
}
func sendFavoriteNotification(to peerID: String, isFavorite: Bool) {
SecureLogger.log("🔔 sendFavoriteNotification called - peerID: \(peerID), isFavorite: \(isFavorite)",
category: .session, level: .debug)
SecureLogger.debug("🔔 sendFavoriteNotification called - peerID: \(peerID), isFavorite: \(isFavorite)", category: .session)
// Include Nostr public key in the notification
var content = isFavorite ? "[FAVORITED]" : "[UNFAVORITED]"
@@ -596,12 +592,10 @@ final class BLEService: NSObject {
// Add our Nostr public key if available
if let myNostrIdentity = try? NostrIdentityBridge.getCurrentNostrIdentity() {
content += ":" + myNostrIdentity.npub
SecureLogger.log("📝 Sending favorite notification with Nostr npub: \(myNostrIdentity.npub)",
category: .session, level: .debug)
SecureLogger.debug("📝 Sending favorite notification with Nostr npub: \(myNostrIdentity.npub)", category: .session)
}
SecureLogger.log("📤 Sending favorite notification to \(peerID): \(content)",
category: .session, level: .debug)
SecureLogger.debug("📤 Sending favorite notification to \(peerID): \(content)", category: .session)
sendPrivateMessage(content, to: peerID, messageID: UUID().uuidString)
}
@@ -611,8 +605,7 @@ final class BLEService: NSObject {
payload.append(contentsOf: receipt.originalMessageID.utf8)
if noiseService.hasEstablishedSession(with: peerID) {
SecureLogger.log("📤 Sending READ receipt for message \(receipt.originalMessageID) to \(peerID)",
category: .session, level: .debug)
SecureLogger.debug("📤 Sending READ receipt for message \(receipt.originalMessageID) to \(peerID)", category: .session)
do {
let encrypted = try noiseService.encrypt(payload, for: peerID)
let packet = BitchatPacket(
@@ -630,7 +623,7 @@ final class BLEService: NSObject {
messageQueue.async { [weak self] in self?.broadcastPacket(packet) }
}
} catch {
SecureLogger.log("Failed to send read receipt: \(error)", category: .noise, level: .error)
SecureLogger.error("Failed to send read receipt: \(error)", category: .noise)
}
} else {
// Queue for after handshake and initiate if needed
@@ -639,8 +632,7 @@ final class BLEService: NSObject {
self.pendingNoisePayloadsAfterHandshake[peerID, default: []].append(payload)
}
if !noiseService.hasSession(with: peerID) { initiateNoiseHandshake(with: peerID) }
SecureLogger.log("🕒 Queued READ receipt for \(peerID) until handshake completes",
category: .session, level: .debug)
SecureLogger.debug("🕒 Queued READ receipt for \(peerID) until handshake completes", category: .session)
}
}
@@ -682,7 +674,7 @@ final class BLEService: NSObject {
messageQueue.async { [weak self] in self?.broadcastPacket(packet) }
}
} catch {
SecureLogger.log("Failed to send verification payload: \(error)", category: .noise, level: .error)
SecureLogger.error("Failed to send verification payload: \(error)", category: .noise)
}
}
@@ -748,7 +740,7 @@ final class BLEService: NSObject {
guard let self = self else { return }
guard content.count <= self.maxMessageLength else {
SecureLogger.log("Message too long: \(content.count) chars", category: .session, level: .error)
SecureLogger.error("Message too long: \(content.count) chars", category: .session)
return
}
@@ -771,7 +763,7 @@ final class BLEService: NSObject {
ttl: self.messageTTL
)
guard let signedPacket = self.noiseService.signPacket(basePacket) else {
SecureLogger.log("❌ Failed to sign public message", category: .security, level: .error)
SecureLogger.error("❌ Failed to sign public message", category: .security)
return
}
// Pre-mark our own broadcast as processed to avoid handling relayed self copy
@@ -789,7 +781,7 @@ final class BLEService: NSObject {
// MARK: - Private Message Handling
private func sendPrivateMessage(_ content: String, to recipientID: String, messageID: String) {
SecureLogger.log("📨 Sending PM to \(recipientID): \(content.prefix(30))...", category: .session, level: .debug)
SecureLogger.debug("📨 Sending PM to \(recipientID): \(content.prefix(30))...", category: .session)
// Check if we have an established Noise session
if noiseService.hasEstablishedSession(with: recipientID) {
@@ -798,7 +790,7 @@ final class BLEService: NSObject {
// Create TLV-encoded private message
let privateMessage = PrivateMessagePacket(messageID: messageID, content: content)
guard let tlvData = privateMessage.encode() else {
SecureLogger.log("Failed to encode private message with TLV", category: .noise, level: .error)
SecureLogger.error("Failed to encode private message with TLV", category: .noise)
return
}
@@ -847,11 +839,11 @@ final class BLEService: NSObject {
self?.delegate?.didUpdateMessageDeliveryStatus(messageID, status: .sent)
}
} catch {
SecureLogger.log("Failed to encrypt message: \(error)", category: .noise, level: .error)
SecureLogger.error("Failed to encrypt message: \(error)", category: .noise)
}
} else {
// Queue message for sending after handshake completes
SecureLogger.log("🤝 No session with \(recipientID), initiating handshake and queueing message", category: .session, level: .debug)
SecureLogger.debug("🤝 No session with \(recipientID), initiating handshake and queueing message", category: .session)
// Queue the message (especially important for favorite notifications)
collectionsQueue.sync(flags: .barrier) {
@@ -896,7 +888,7 @@ final class BLEService: NSObject {
}
}
} catch {
SecureLogger.log("Failed to initiate handshake: \(error)", category: .noise, level: .error)
SecureLogger.error("Failed to initiate handshake: \(error)", category: .noise)
}
}
@@ -910,8 +902,7 @@ final class BLEService: NSObject {
guard let messages = pendingMessages, !messages.isEmpty else { return }
SecureLogger.log("📤 Sending \(messages.count) pending messages after handshake to \(peerID)",
category: .session, level: .debug)
SecureLogger.debug("📤 Sending \(messages.count) pending messages after handshake to \(peerID)", category: .session)
// Send each pending message directly (we know session is established)
for (content, messageID) in messages {
@@ -919,7 +910,7 @@ final class BLEService: NSObject {
// Use the same TLV format as normal sends to keep receiver decoding consistent
let privateMessage = PrivateMessagePacket(messageID: messageID, content: content)
guard let tlvData = privateMessage.encode() else {
SecureLogger.log("Failed to encode pending private message TLV", category: .noise, level: .error)
SecureLogger.error("Failed to encode pending private message TLV", category: .noise)
continue
}
@@ -946,11 +937,9 @@ final class BLEService: NSObject {
self?.delegate?.didUpdateMessageDeliveryStatus(messageID, status: .sent)
}
SecureLogger.log("✅ Sent pending message \(messageID) to \(peerID) after handshake",
category: .session, level: .debug)
SecureLogger.debug("✅ Sent pending message \(messageID) to \(peerID) after handshake", category: .session)
} catch {
SecureLogger.log("Failed to send pending message after handshake: \(error)",
category: .noise, level: .error)
SecureLogger.error("Failed to send pending message after handshake: \(error)", category: .noise)
// Notify delegate of failure
notifyUI { [weak self] in
@@ -966,7 +955,7 @@ final class BLEService: NSObject {
// Encode once using a small per-type padding policy, then delegate by type
let padForBLE = padPolicy(for: packet.type)
guard let data = packet.toBinaryData(padding: padForBLE) else {
SecureLogger.log("❌ Failed to convert packet to binary data", category: .session, level: .error)
SecureLogger.error("❌ Failed to convert packet to binary data", category: .session)
return
}
if packet.type == MessageType.noiseEncrypted.rawValue {
@@ -1037,7 +1026,7 @@ final class BLEService: NSObject {
guard let self = self else { return }
if self.pendingNotifications.count < TransportConfig.blePendingNotificationsCapCount {
self.pendingNotifications.append((data: data, centrals: [central]))
SecureLogger.log("📋 Queued encrypted packet for retry (notification queue full)", category: .session, level: .debug)
SecureLogger.debug("📋 Queued encrypted packet for retry (notification queue full)", category: .session)
}
}
}
@@ -1150,7 +1139,7 @@ final class BLEService: NSObject {
if byMsg[msgID] == nil {
byMsg[msgID] = (packet: packet, enqueuedAt: Date())
self.pendingDirectedRelays[recipientPeerID] = byMsg
SecureLogger.log("🧳 Spooling directed packet for \(recipientPeerID) mid=\(msgID.prefix(8))", category: .session, level: .debug)
SecureLogger.debug("🧳 Spooling directed packet for \(recipientPeerID) mid=\(msgID.prefix(8))", category: .session)
}
}
}
@@ -1322,7 +1311,7 @@ final class BLEService: NSObject {
if let originalPacket = BinaryProtocol.decode(reassembled) {
handleReceivedPacket(originalPacket, from: peerID)
} else {
SecureLogger.log("❌ Failed to decode reassembled packet (type=\(originalType), total=\(total))", category: .session, level: .error)
SecureLogger.error("❌ Failed to decode reassembled packet (type=\(originalType), total=\(total))", category: .session)
}
// Cleanup
@@ -1342,8 +1331,7 @@ final class BLEService: NSObject {
// Only log non-announce packets to reduce noise
if packet.type != MessageType.announce.rawValue {
// Log packet details for debugging
SecureLogger.log("📦 Handling packet type \(packet.type) from \(senderID), messageID: \(messageID)",
category: .session, level: .debug)
SecureLogger.debug("📦 Handling packet type \(packet.type) from \(senderID), messageID: \(messageID)", category: .session)
}
// Efficient deduplication
@@ -1352,8 +1340,7 @@ final class BLEService: NSObject {
// Announce packets (type 1) are sent every 10 seconds for peer discovery
// It's normal to see these as duplicates - don't log them to reduce noise
if packet.type != MessageType.announce.rawValue {
SecureLogger.log("⚠️ Duplicate packet ignored: \(messageID)",
category: .session, level: .debug)
SecureLogger.debug("⚠️ Duplicate packet ignored: \(messageID)", category: .session)
}
// In sparse graphs (<=2 neighbors), keep the pending relay to ensure bridging.
// In denser graphs, cancel the pending relay to reduce redundant floods.
@@ -1406,7 +1393,7 @@ final class BLEService: NSObject {
handleLeave(packet, from: senderID)
default:
SecureLogger.log("⚠️ Unknown message type: \(packet.type)", category: .session, level: .warning)
SecureLogger.warning("⚠️ Unknown message type: \(packet.type)", category: .session)
break
}
@@ -1446,7 +1433,7 @@ final class BLEService: NSObject {
private func handleAnnounce(_ packet: BitchatPacket, from peerID: String) {
guard let announcement = AnnouncementPacket.decode(from: packet.payload) else {
SecureLogger.log("❌ Failed to decode announce packet from \(peerID)", category: .session, level: .error)
SecureLogger.error("❌ Failed to decode announce packet from \(peerID)", category: .session)
return
}
@@ -1454,7 +1441,7 @@ final class BLEService: NSObject {
// This helps detect relayed or spoofed announces. Only warn in release; assert in debug.
let derivedFromKey = PeerIDUtils.derivePeerID(fromPublicKey: announcement.noisePublicKey)
if derivedFromKey != peerID {
SecureLogger.log("⚠️ Announce sender mismatch: derived \(derivedFromKey.prefix(8))… vs packet \(peerID.prefix(8))", category: .security, level: .warning)
SecureLogger.warning("⚠️ Announce sender mismatch: derived \(derivedFromKey.prefix(8))… vs packet \(peerID.prefix(8))", category: .security)
}
@@ -1471,11 +1458,11 @@ final class BLEService: NSObject {
if packet.signature != nil {
verifiedAnnounce = noiseService.verifyPacketSignature(packet, publicKey: announcement.signingPublicKey)
if !verifiedAnnounce {
SecureLogger.log("⚠️ Signature verification for announce failed \(peerID.prefix(8))", category: .security, level: .warning)
SecureLogger.warning("⚠️ Signature verification for announce failed \(peerID.prefix(8))", category: .security)
}
}
if let existingKey = existingPeerForVerify?.noisePublicKey, existingKey != announcement.noisePublicKey {
SecureLogger.log("⚠️ Announce key mismatch for \(peerID.prefix(8))… — keeping unverified", category: .security, level: .warning)
SecureLogger.warning("⚠️ Announce key mismatch for \(peerID.prefix(8))… — keeping unverified", category: .security)
verifiedAnnounce = false
}
@@ -1508,7 +1495,7 @@ final class BLEService: NSObject {
// Require verified announce; ignore otherwise (no backward compatibility)
if !verified {
SecureLogger.log("❌ Ignoring unverified announce from \(peerID.prefix(8))", category: .security, level: .warning)
SecureLogger.warning("❌ Ignoring unverified announce from \(peerID.prefix(8))", category: .security)
return
}
@@ -1541,17 +1528,17 @@ final class BLEService: NSObject {
if isDirectAnnounce || hasPeripheralConnection || hasCentralSubscription {
let now = Date()
if existingPeer == nil {
SecureLogger.log("🆕 New peer: \(announcement.nickname)", category: .session, level: .debug)
SecureLogger.debug("🆕 New peer: \(announcement.nickname)", category: .session)
} else if wasDisconnected {
// Debounce 'reconnected' logs within short window
if let last = lastReconnectLogAt[peerID], now.timeIntervalSince(last) < TransportConfig.bleReconnectLogDebounceSeconds {
// Skip duplicate log
} else {
SecureLogger.log("🔄 Peer \(announcement.nickname) reconnected", category: .session, level: .debug)
SecureLogger.debug("🔄 Peer \(announcement.nickname) reconnected", category: .session)
lastReconnectLogAt[peerID] = now
}
} else if existingPeer?.nickname != announcement.nickname {
SecureLogger.log("🔄 Peer \(peerID) changed nickname: \(existingPeer?.nickname ?? "Unknown") -> \(announcement.nickname)", category: .session, level: .debug)
SecureLogger.debug("🔄 Peer \(peerID) changed nickname: \(existingPeer?.nickname ?? "Unknown") -> \(announcement.nickname)", category: .session)
}
}
}
@@ -1661,12 +1648,12 @@ final class BLEService: NSObject {
}
guard accepted else {
SecureLogger.log("🚫 Dropping public message from unverified or unknown peer \(peerID.prefix(8))", category: .security, level: .warning)
SecureLogger.warning("🚫 Dropping public message from unverified or unknown peer \(peerID.prefix(8))", category: .security)
return
}
guard let content = String(data: packet.payload, encoding: .utf8) else {
SecureLogger.log("❌ Failed to decode message payload as UTF-8", category: .session, level: .error)
SecureLogger.error("❌ Failed to decode message payload as UTF-8", category: .session)
return
}
// Determine if we have a direct link to the sender
@@ -1678,7 +1665,7 @@ final class BLEService: NSObject {
}
let pathTag = hasDirectLink ? "direct" : "mesh"
SecureLogger.log("💬 [\(senderNickname)] TTL:\(packet.ttl) (\(pathTag)): \(String(content.prefix(50)))\(content.count > 50 ? "..." : "")", category: .session, level: .debug)
SecureLogger.debug("💬 [\(senderNickname)] TTL:\(packet.ttl) (\(pathTag)): \(String(content.prefix(50)))\(content.count > 50 ? "..." : "")", category: .session)
let ts = Date(timeIntervalSince1970: Double(packet.timestamp) / 1000)
notifyUI { [weak self] in
@@ -1710,7 +1697,7 @@ final class BLEService: NSObject {
// Session establishment will trigger onPeerAuthenticated callback
// which will send any pending messages at the right time
} catch {
SecureLogger.log("Failed to process handshake: \(error)", category: .noise, level: .error)
SecureLogger.error("Failed to process handshake: \(error)", category: .noise)
// Try initiating a new handshake
if !noiseService.hasSession(with: peerID) {
initiateNoiseHandshake(with: peerID)
@@ -1720,17 +1707,16 @@ final class BLEService: NSObject {
}
private func handleNoiseEncrypted(_ packet: BitchatPacket, from peerID: String) {
SecureLogger.log("🔐 handleNoiseEncrypted called for packet from \(peerID)",
category: .noise, level: .debug)
SecureLogger.debug("🔐 handleNoiseEncrypted called for packet from \(peerID)", category: .noise)
guard let recipientID = packet.recipientID else {
SecureLogger.log("⚠️ Encrypted message has no recipient ID", category: .session, level: .warning)
SecureLogger.warning("⚠️ Encrypted message has no recipient ID", category: .session)
return
}
let recipientHex = recipientID.hexEncodedString()
if recipientHex != myPeerID {
SecureLogger.log("🔐 Encrypted message not for me (for \(recipientHex), I am \(myPeerID))", category: .session, level: .debug)
SecureLogger.debug("🔐 Encrypted message not for me (for \(recipientHex), I am \(myPeerID))", category: .session)
return
}
@@ -1772,19 +1758,17 @@ final class BLEService: NSObject {
self?.delegate?.didReceiveNoisePayload(from: peerID, type: .verifyResponse, payload: Data(payloadData), timestamp: ts)
}
default:
SecureLogger.log("⚠️ Unknown noise payload type: \(payloadType)", category: .noise, level: .warning)
SecureLogger.warning("⚠️ Unknown noise payload type: \(payloadType)", category: .noise)
}
} catch NoiseEncryptionError.sessionNotEstablished {
// We received an encrypted message before establishing a session with this peer.
// Trigger a handshake so future messages can be decrypted.
SecureLogger.log("🔑 Encrypted message from \(peerID) without session; initiating handshake",
category: .noise, level: .debug)
SecureLogger.debug("🔑 Encrypted message from \(peerID) without session; initiating handshake", category: .noise)
if !noiseService.hasSession(with: peerID) {
initiateNoiseHandshake(with: peerID)
}
} catch {
SecureLogger.log("❌ Failed to decrypt message from \(peerID): \(error)",
category: .noise, level: .error)
SecureLogger.error("❌ Failed to decrypt message from \(peerID): \(error)", category: .noise)
}
}
@@ -1808,7 +1792,7 @@ final class BLEService: NSObject {
// MARK: - Helper Functions
private func sendLeave() {
SecureLogger.log("👋 Sending leave announcement", category: .session, level: .debug)
SecureLogger.debug("👋 Sending leave announcement", category: .session)
let packet = BitchatPacket(
type: MessageType.leave.rawValue,
ttl: messageTTL,
@@ -1845,7 +1829,7 @@ final class BLEService: NSObject {
)
guard let payload = announcement.encode() else {
SecureLogger.log("❌ Failed to encode announce packet", category: .session, level: .error)
SecureLogger.error("❌ Failed to encode announce packet", category: .session)
return
}
@@ -1862,7 +1846,7 @@ final class BLEService: NSObject {
// Sign the packet using the noise private key
guard let signedPacket = noiseService.signPacket(packet) else {
SecureLogger.log("❌ Failed to sign announce packet", category: .security, level: .error)
SecureLogger.error("❌ Failed to sign announce packet", category: .security)
return
}
@@ -1895,7 +1879,7 @@ final class BLEService: NSObject {
)
broadcastPacket(packet)
} catch {
SecureLogger.log("Failed to send delivery ACK: \(error)", category: .noise, level: .error)
SecureLogger.error("Failed to send delivery ACK: \(error)", category: .noise)
}
} else {
// Queue for after handshake and initiate if needed
@@ -1904,8 +1888,7 @@ final class BLEService: NSObject {
self.pendingNoisePayloadsAfterHandshake[peerID, default: []].append(payload)
}
if !noiseService.hasSession(with: peerID) { initiateNoiseHandshake(with: peerID) }
SecureLogger.log("🕒 Queued DELIVERED ack for \(peerID) until handshake completes",
category: .session, level: .debug)
SecureLogger.debug("🕒 Queued DELIVERED ack for \(peerID) until handshake completes", category: .session)
}
}
@@ -1916,8 +1899,7 @@ final class BLEService: NSObject {
return list
}
guard !payloads.isEmpty else { return }
SecureLogger.log("📤 Sending \(payloads.count) pending noise payloads to \(peerID) after handshake",
category: .session, level: .debug)
SecureLogger.debug("📤 Sending \(payloads.count) pending noise payloads to \(peerID) after handshake", category: .session)
for payload in payloads {
do {
let encrypted = try noiseService.encrypt(payload, for: peerID)
@@ -1932,8 +1914,7 @@ final class BLEService: NSObject {
)
broadcastPacket(packet)
} catch {
SecureLogger.log("❌ Failed to send pending noise payload to \(peerID): \(error)",
category: .noise, level: .error)
SecureLogger.error("❌ Failed to send pending noise payload to \(peerID): \(error)", category: .noise)
}
}
}
@@ -2103,8 +2084,7 @@ final class BLEService: NSObject {
// Cleanup: remove peers that are not connected and past reachability retention
if !peer.isConnected {
if age > retention {
SecureLogger.log("🗑️ Removing stale peer after reachability window: \(peerID) (\(peer.nickname))",
category: .session, level: .debug)
SecureLogger.debug("🗑️ Removing stale peer after reachability window: \(peerID) (\(peer.nickname))", category: .session)
peers.removeValue(forKey: peerID)
removedOfflineCount += 1
}
@@ -2395,8 +2375,7 @@ extension BLEService: CBCentralManagerDelegate {
peripheral.delegate = self
// Connect to the peripheral with options for faster connection
SecureLogger.log("📱 Connect: \(advertisedName) [RSSI:\(rssiValue)]",
category: .session, level: .debug)
SecureLogger.debug("📱 Connect: \(advertisedName) [RSSI:\(rssiValue)]", category: .session)
// Use connection options for faster reconnection
let options: [String: Any] = [
@@ -2415,8 +2394,7 @@ extension BLEService: CBCentralManagerDelegate {
state.isConnecting && !state.isConnected else { return }
// Connection timed out - cancel it
SecureLogger.log("⏱️ Timeout: \(advertisedName)",
category: .session, level: .debug)
SecureLogger.debug("⏱️ Timeout: \(advertisedName)", category: .session)
central.cancelPeripheralConnection(peripheral)
self.peripherals[peripheralID] = nil
self.recentConnectTimeouts[peripheralID] = Date()
@@ -2449,7 +2427,7 @@ func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeriph
failureCounts[peripheralID] = 0
recentConnectTimeouts.removeValue(forKey: peripheralID)
SecureLogger.log("✅ Connected: \(peripheral.name ?? "Unknown") [\(peripheralID)]", category: .session, level: .debug)
SecureLogger.debug("✅ Connected: \(peripheral.name ?? "Unknown") [\(peripheralID)]", category: .session)
// Discover services
peripheral.discoverServices([BLEService.serviceUUID])
@@ -2461,8 +2439,7 @@ func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeriph
// Find the peer ID if we have it
let peerID = peripherals[peripheralID]?.peerID
SecureLogger.log("📱 Disconnect: \(peerID ?? peripheralID)\(error != nil ? " (\(error!.localizedDescription))" : "")",
category: .session, level: .debug)
SecureLogger.debug("📱 Disconnect: \(peerID ?? peripheralID)\(error != nil ? " (\(error!.localizedDescription))" : "")", category: .session)
// If disconnect carried an error (often timeout), apply short backoff to avoid thrash
if error != nil {
@@ -2517,7 +2494,7 @@ func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeriph
// Clean up the references
peripherals.removeValue(forKey: peripheralID)
SecureLogger.log("❌ Failed to connect to peripheral: \(peripheral.name ?? "Unknown") [\(peripheralID)] - Error: \(error?.localizedDescription ?? "Unknown")", category: .session, level: .error)
SecureLogger.error("❌ Failed to connect to peripheral: \(peripheral.name ?? "Unknown") [\(peripheralID)] - Error: \(error?.localizedDescription ?? "Unknown")", category: .session)
failureCounts[peripheralID, default: 0] += 1
// Try next candidate
bleQueue.async { [weak self] in self?.tryConnectFromQueue() }
@@ -2590,7 +2567,7 @@ extension BLEService {
]
central.connect(peripheral, options: options)
lastGlobalConnectAttempt = Date()
SecureLogger.log("⏩ Queue connect: \(candidate.name) [RSSI:\(candidate.rssi)]", category: .session, level: .debug)
SecureLogger.debug("⏩ Queue connect: \(candidate.name) [RSSI:\(candidate.rssi)]", category: .session)
}
}
@@ -2635,7 +2612,7 @@ extension BLEService {
extension BLEService: CBPeripheralDelegate {
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if let error = error {
SecureLogger.log("❌ Error discovering services for \(peripheral.name ?? "Unknown"): \(error.localizedDescription)", category: .session, level: .error)
SecureLogger.error("❌ Error discovering services for \(peripheral.name ?? "Unknown"): \(error.localizedDescription)", category: .session)
// Retry service discovery after a delay
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
guard peripheral.state == .connected else { return }
@@ -2645,7 +2622,7 @@ extension BLEService: CBPeripheralDelegate {
}
guard let services = peripheral.services else {
SecureLogger.log("⚠️ No services discovered for \(peripheral.name ?? "Unknown")", category: .session, level: .warning)
SecureLogger.warning("⚠️ No services discovered for \(peripheral.name ?? "Unknown")", category: .session)
return
}
@@ -2661,12 +2638,12 @@ extension BLEService: CBPeripheralDelegate {
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
if let error = error {
SecureLogger.log("❌ Error discovering characteristics for \(peripheral.name ?? "Unknown"): \(error.localizedDescription)", category: .session, level: .error)
SecureLogger.error("❌ Error discovering characteristics for \(peripheral.name ?? "Unknown"): \(error.localizedDescription)", category: .session)
return
}
guard let characteristic = service.characteristics?.first(where: { $0.uuid == BLEService.characteristicUUID }) else {
SecureLogger.log("⚠️ No matching characteristic found for \(peripheral.name ?? "Unknown")", category: .session, level: .warning)
SecureLogger.warning("⚠️ No matching characteristic found for \(peripheral.name ?? "Unknown")", category: .session)
return
}
@@ -2683,7 +2660,7 @@ extension BLEService: CBPeripheralDelegate {
// Verify characteristic supports reliable writes
if !characteristic.properties.contains(.write) {
SecureLogger.log("⚠️ Characteristic doesn't support reliable writes (withResponse)!", category: .session, level: .warning)
SecureLogger.warning("⚠️ Characteristic doesn't support reliable writes (withResponse)!", category: .session)
}
// Store characteristic in our consolidated structure
@@ -2696,7 +2673,7 @@ extension BLEService: CBPeripheralDelegate {
// Subscribe for notifications
if characteristic.properties.contains(.notify) {
peripheral.setNotifyValue(true, for: characteristic)
SecureLogger.log("🔔 Subscribed to notifications from \(peripheral.name ?? "Unknown")", category: .session, level: .debug)
SecureLogger.debug("🔔 Subscribed to notifications from \(peripheral.name ?? "Unknown")", category: .session)
// Send announce after subscription is confirmed (force send for new connection)
messageQueue.asyncAfter(deadline: .now() + TransportConfig.blePostSubscribeAnnounceDelaySeconds) { [weak self] in
@@ -2707,18 +2684,18 @@ extension BLEService: CBPeripheralDelegate {
self?.rebroadcastRecentAnnounces()
}
} else {
SecureLogger.log("⚠️ Characteristic does not support notifications", category: .session, level: .warning)
SecureLogger.warning("⚠️ Characteristic does not support notifications", category: .session)
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if let error = error {
SecureLogger.log("❌ Error receiving notification: \(error.localizedDescription)", category: .session, level: .error)
SecureLogger.error("❌ Error receiving notification: \(error.localizedDescription)", category: .session)
return
}
guard let data = characteristic.value else {
SecureLogger.log("⚠️ No data in notification", category: .session, level: .warning)
SecureLogger.warning("⚠️ No data in notification", category: .session)
return
}
@@ -2728,8 +2705,7 @@ extension BLEService: CBPeripheralDelegate {
guard let packet = BinaryProtocol.decode(data) else {
// Avoid dumping entire payload; log size and short prefix for diagnostics
let prefix = data.prefix(16).map { String(format: "%02x", $0) }.joined(separator: " ")
SecureLogger.log("❌ Failed to decode notification packet (len=\(data.count), prefix=\(prefix))",
category: .session, level: .error)
SecureLogger.error("❌ Failed to decode notification packet (len=\(data.count), prefix=\(prefix))", category: .session)
return
}
@@ -2737,7 +2713,7 @@ extension BLEService: CBPeripheralDelegate {
let senderID = packet.senderID.hexEncodedString()
// Only log non-announce packets
if packet.type != MessageType.announce.rawValue {
SecureLogger.log("📦 Decoded notification packet type: \(packet.type) from sender: \(senderID)", category: .session, level: .debug)
SecureLogger.debug("📦 Decoded notification packet type: \(packet.type) from sender: \(senderID)", category: .session)
}
let peripheralUUID = peripheral.identifier.uuidString
@@ -2775,10 +2751,10 @@ extension BLEService: CBPeripheralDelegate {
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
if let error = error {
SecureLogger.log("❌ Write failed to \(peripheral.name ?? peripheral.identifier.uuidString): \(error.localizedDescription)", category: .session, level: .error)
SecureLogger.error("❌ Write failed to \(peripheral.name ?? peripheral.identifier.uuidString): \(error.localizedDescription)", category: .session)
// Don't retry - just log the error
} else {
SecureLogger.log("✅ Write confirmed to \(peripheral.name ?? peripheral.identifier.uuidString)", category: .session, level: .debug)
SecureLogger.debug("✅ Write confirmed to \(peripheral.name ?? peripheral.identifier.uuidString)", category: .session)
}
}
@@ -2788,14 +2764,14 @@ extension BLEService: CBPeripheralDelegate {
}
func peripheral(_ peripheral: CBPeripheral, didModifyServices invalidatedServices: [CBService]) {
SecureLogger.log("⚠️ Services modified for \(peripheral.name ?? peripheral.identifier.uuidString)", category: .session, level: .warning)
SecureLogger.warning("⚠️ Services modified for \(peripheral.name ?? peripheral.identifier.uuidString)", category: .session)
// Check if our service was invalidated (peer app quit)
let hasOurService = peripheral.services?.contains { $0.uuid == BLEService.serviceUUID } ?? false
if !hasOurService {
// Service is gone - disconnect
SecureLogger.log("❌ BitChat service removed - disconnecting from \(peripheral.name ?? peripheral.identifier.uuidString)", category: .session, level: .warning)
SecureLogger.warning("❌ BitChat service removed - disconnecting from \(peripheral.name ?? peripheral.identifier.uuidString)", category: .session)
centralManager?.cancelPeripheralConnection(peripheral)
} else {
// Try to rediscover
@@ -2805,9 +2781,9 @@ extension BLEService: CBPeripheralDelegate {
func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
if let error = error {
SecureLogger.log("❌ Error updating notification state: \(error.localizedDescription)", category: .session, level: .error)
SecureLogger.error("❌ Error updating notification state: \(error.localizedDescription)", category: .session)
} else {
SecureLogger.log("🔔 Notification state updated for \(peripheral.name ?? peripheral.identifier.uuidString): \(characteristic.isNotifying ? "ON" : "OFF")", category: .session, level: .debug)
SecureLogger.debug("🔔 Notification state updated for \(peripheral.name ?? peripheral.identifier.uuidString): \(characteristic.isNotifying ? "ON" : "OFF")", category: .session)
// If notifications are now on, send an announce to ensure this peer knows about us
if characteristic.isNotifying {
@@ -2822,7 +2798,7 @@ extension BLEService: CBPeripheralDelegate {
extension BLEService: CBPeripheralManagerDelegate {
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
SecureLogger.log("📡 Peripheral manager state: \(peripheral.state.rawValue)", category: .session, level: .debug)
SecureLogger.debug("📡 Peripheral manager state: \(peripheral.state.rawValue)", category: .session)
if peripheral.state == .poweredOn {
// Remove all services first to ensure clean state
@@ -2841,28 +2817,28 @@ extension BLEService: CBPeripheralManagerDelegate {
service.characteristics = [characteristic!]
// Add service (advertising will start in didAdd delegate)
SecureLogger.log("🔧 Adding BLE service...", category: .session, level: .debug)
SecureLogger.debug("🔧 Adding BLE service...", category: .session)
peripheral.add(service)
}
}
func peripheralManager(_ peripheral: CBPeripheralManager, didAdd service: CBService, error: Error?) {
if let error = error {
SecureLogger.log("❌ Failed to add service: \(error.localizedDescription)", category: .session, level: .error)
SecureLogger.error("❌ Failed to add service: \(error.localizedDescription)", category: .session)
return
}
SecureLogger.log("✅ Service added successfully, starting advertising", category: .session, level: .debug)
SecureLogger.debug("✅ Service added successfully, starting advertising", category: .session)
// Start advertising after service is confirmed added
let adData = buildAdvertisementData()
peripheral.startAdvertising(adData)
SecureLogger.log("📡 Started advertising (LocalName: \((adData[CBAdvertisementDataLocalNameKey] as? String) != nil ? "on" : "off"), ID: \(myPeerID.prefix(8))…)", category: .session, level: .debug)
SecureLogger.debug("📡 Started advertising (LocalName: \((adData[CBAdvertisementDataLocalNameKey] as? String) != nil ? "on" : "off"), ID: \(myPeerID.prefix(8))…)", category: .session)
}
func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didSubscribeTo characteristic: CBCharacteristic) {
SecureLogger.log("📥 Central subscribed: \(central.identifier.uuidString)", category: .session, level: .debug)
SecureLogger.debug("📥 Central subscribed: \(central.identifier.uuidString)", category: .session)
subscribedCentrals.append(central)
// Send announce to the newly subscribed central after a small delay to avoid overwhelming
messageQueue.asyncAfter(deadline: .now() + TransportConfig.blePostAnnounceDelaySeconds) { [weak self] in
@@ -2875,12 +2851,12 @@ extension BLEService: CBPeripheralManagerDelegate {
}
func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didUnsubscribeFrom characteristic: CBCharacteristic) {
SecureLogger.log("📤 Central unsubscribed: \(central.identifier.uuidString)", category: .session, level: .debug)
SecureLogger.debug("📤 Central unsubscribed: \(central.identifier.uuidString)", category: .session)
subscribedCentrals.removeAll { $0.identifier == central.identifier }
// Ensure we're still advertising for other devices to find us
if peripheral.isAdvertising == false {
SecureLogger.log("📡 Restarting advertising after central unsubscribed", category: .session, level: .debug)
SecureLogger.debug("📡 Restarting advertising after central unsubscribed", category: .session)
peripheral.startAdvertising(buildAdvertisementData())
}
@@ -2914,7 +2890,7 @@ extension BLEService: CBPeripheralManagerDelegate {
}
func peripheralManagerIsReady(toUpdateSubscribers peripheral: CBPeripheralManager) {
SecureLogger.log("📤 Peripheral manager ready to send more notifications", category: .session, level: .debug)
SecureLogger.debug("📤 Peripheral manager ready to send more notifications", category: .session)
// Retry pending notifications now that queue has space
collectionsQueue.async(flags: .barrier) { [weak self] in
@@ -2933,12 +2909,10 @@ extension BLEService: CBPeripheralManagerDelegate {
if !success {
// Still full, re-queue
self.pendingNotifications.append((data: data, centrals: centrals))
SecureLogger.log("⚠️ Notification queue still full, re-queuing",
category: .session, level: .debug)
SecureLogger.debug("⚠️ Notification queue still full, re-queuing", category: .session)
break // Stop trying, wait for next ready callback
} else {
SecureLogger.log("✅ Sent pending notification from retry queue",
category: .session, level: .debug)
SecureLogger.debug("✅ Sent pending notification from retry queue", category: .session)
}
} else {
// Broadcast to all
@@ -2952,8 +2926,7 @@ extension BLEService: CBPeripheralManagerDelegate {
}
if !self.pendingNotifications.isEmpty {
SecureLogger.log("📋 Still have \(self.pendingNotifications.count) pending notifications",
category: .session, level: .debug)
SecureLogger.debug("📋 Still have \(self.pendingNotifications.count) pending notifications", category: .session)
}
}
}
@@ -2961,7 +2934,7 @@ extension BLEService: CBPeripheralManagerDelegate {
func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveWrite requests: [CBATTRequest]) {
// Suppress logs for single write requests to reduce noise
if requests.count > 1 {
SecureLogger.log("📥 Received \(requests.count) write requests from central", category: .session, level: .debug)
SecureLogger.debug("📥 Received \(requests.count) write requests from central", category: .session)
}
// IMPORTANT: Respond immediately to prevent timeouts!
@@ -3000,7 +2973,7 @@ extension BLEService: CBPeripheralManagerDelegate {
if combined.count >= 2 {
let peekType = combined[1]
if peekType != MessageType.announce.rawValue {
SecureLogger.log("📥 Accumulated write from central \(centralUUID): size=\(combined.count) (+\(appendedBytes)) bytes (type=\(peekType)), offsets=\(offsets)", category: .session, level: .debug)
SecureLogger.debug("📥 Accumulated write from central \(centralUUID): size=\(combined.count) (+\(appendedBytes)) bytes (type=\(peekType)), offsets=\(offsets)", category: .session)
}
}
@@ -3010,7 +2983,7 @@ extension BLEService: CBPeripheralManagerDelegate {
pendingWriteBuffers.removeValue(forKey: centralUUID)
let senderID = packet.senderID.hexEncodedString()
if packet.type != MessageType.announce.rawValue {
SecureLogger.log("📦 Decoded (combined) packet type: \(packet.type) from sender: \(senderID)", category: .session, level: .debug)
SecureLogger.debug("📦 Decoded (combined) packet type: \(packet.type) from sender: \(senderID)", category: .session)
}
if !subscribedCentrals.contains(sorted[0].central) {
subscribedCentrals.append(sorted[0].central)
@@ -3035,12 +3008,12 @@ extension BLEService: CBPeripheralManagerDelegate {
// If buffer grows suspiciously large, reset to avoid memory leak
if combined.count > TransportConfig.blePendingWriteBufferCapBytes { // cap for safety
pendingWriteBuffers.removeValue(forKey: centralUUID)
SecureLogger.log("⚠️ Dropping oversized pending write buffer (\(combined.count) bytes) for central \(centralUUID)", category: .session, level: .warning)
SecureLogger.warning("⚠️ Dropping oversized pending write buffer (\(combined.count) bytes) for central \(centralUUID)", category: .session)
}
// If this was a single short write and still failed, log the raw chunk for debugging
if !hasMultiple, let only = sorted.first, let raw = only.value {
let prefix = raw.prefix(16).map { String(format: "%02x", $0) }.joined(separator: " ")
SecureLogger.log("❌ Failed to decode packet from central (len=\(raw.count), prefix=\(prefix))", category: .session, level: .error)
SecureLogger.error("❌ Failed to decode packet from central (len=\(raw.count), prefix=\(prefix))", category: .session)
}
}
}
@@ -47,8 +47,7 @@ final class FavoritesPersistenceService: ObservableObject {
peerNostrPublicKey: String? = nil,
peerNickname: String
) {
SecureLogger.log("⭐️ Adding favorite: \(peerNickname) (\(peerNoisePublicKey.hexEncodedString()))",
category: .session, level: .info)
SecureLogger.info("⭐️ Adding favorite: \(peerNickname) (\(peerNoisePublicKey.hexEncodedString()))", category: .session)
let existing = favorites[peerNoisePublicKey]
@@ -64,8 +63,7 @@ final class FavoritesPersistenceService: ObservableObject {
// Log if this creates a mutual favorite
if relationship.isMutual {
SecureLogger.log("💕 Mutual favorite relationship established with \(peerNickname)!",
category: .session, level: .info)
SecureLogger.info("💕 Mutual favorite relationship established with \(peerNickname)!", category: .session)
}
favorites[peerNoisePublicKey] = relationship
@@ -83,8 +81,7 @@ final class FavoritesPersistenceService: ObservableObject {
func removeFavorite(peerNoisePublicKey: Data) {
guard let existing = favorites[peerNoisePublicKey] else { return }
SecureLogger.log("⭐️ Removing favorite: \(existing.peerNickname) (\(peerNoisePublicKey.hexEncodedString()))",
category: .session, level: .info)
SecureLogger.info("⭐️ Removing favorite: \(existing.peerNickname) (\(peerNoisePublicKey.hexEncodedString()))", category: .session)
// If they still favorite us, keep the record but mark us as not favoriting
if existing.theyFavoritedUs {
@@ -125,8 +122,7 @@ final class FavoritesPersistenceService: ObservableObject {
let existing = favorites[peerNoisePublicKey]
let displayName = peerNickname ?? existing?.peerNickname ?? "Unknown"
SecureLogger.log("📨 Received favorite notification: \(displayName) \(favorited ? "favorited" : "unfavorited") us",
category: .session, level: .info)
SecureLogger.info("📨 Received favorite notification: \(displayName) \(favorited ? "favorited" : "unfavorited") us", category: .session)
let relationship = FavoriteRelationship(
peerNoisePublicKey: peerNoisePublicKey,
@@ -147,8 +143,7 @@ final class FavoritesPersistenceService: ObservableObject {
// Check if this creates a mutual favorite
if relationship.isMutual {
SecureLogger.log("💕 Mutual favorite relationship established with \(displayName)!",
category: .session, level: .info)
SecureLogger.info("💕 Mutual favorite relationship established with \(displayName)!", category: .session)
}
}
@@ -240,15 +235,13 @@ final class FavoritesPersistenceService: ObservableObject {
/// Update noise public key when peer reconnects with new ID
func updateNoisePublicKey(from oldKey: Data, to newKey: Data, peerNickname: String) {
guard let existing = favorites[oldKey] else {
SecureLogger.log("⚠️ Cannot update noise key - no favorite found for \(oldKey.hexEncodedString())",
category: .session, level: .warning)
SecureLogger.warning("⚠️ Cannot update noise key - no favorite found for \(oldKey.hexEncodedString())", category: .session)
return
}
// Check if we already have a favorite with the new key
if favorites[newKey] != nil {
SecureLogger.log("⚠️ Favorite already exists with new key \(newKey.hexEncodedString()), removing old entry",
category: .session, level: .warning)
SecureLogger.warning("⚠️ Favorite already exists with new key \(newKey.hexEncodedString()), removing old entry", category: .session)
favorites.removeValue(forKey: oldKey)
saveFavorites()
return
@@ -302,7 +295,7 @@ final class FavoritesPersistenceService: ObservableObject {
/// Clear all favorites - used for panic mode
func clearAllFavorites() {
SecureLogger.log("🧹 Clearing all favorites (panic mode)", category: .session, level: .warning)
SecureLogger.warning("🧹 Clearing all favorites (panic mode)", category: .session)
favorites.removeAll()
saveFavorites()
@@ -336,7 +329,7 @@ final class FavoritesPersistenceService: ObservableObject {
// Successfully saved favorites
} catch {
SecureLogger.log("Failed to save favorites: \(error)", category: .session, level: .error)
SecureLogger.error("Failed to save favorites: \(error)", category: .session)
}
}
@@ -354,14 +347,12 @@ final class FavoritesPersistenceService: ObservableObject {
let decoder = JSONDecoder()
let relationships = try decoder.decode([FavoriteRelationship].self, from: data)
SecureLogger.log("✅ Loaded \(relationships.count) favorite relationships",
category: .session, level: .info)
SecureLogger.info("✅ Loaded \(relationships.count) favorite relationships", category: .session)
// Log Nostr public key info
for relationship in relationships {
if relationship.peerNostrPublicKey == nil {
SecureLogger.log("⚠️ No Nostr public key stored for '\(relationship.peerNickname)'",
category: .session, level: .warning)
SecureLogger.warning("⚠️ No Nostr public key stored for '\(relationship.peerNickname)'", category: .session)
}
}
@@ -372,8 +363,7 @@ final class FavoritesPersistenceService: ObservableObject {
for relationship in relationships {
// Check for duplicates by public key (the actual unique identifier)
if let existing = seenPublicKeys[relationship.peerNoisePublicKey] {
SecureLogger.log("⚠️ Duplicate favorite found for public key \(relationship.peerNoisePublicKey.hexEncodedString()) - nicknames: '\(existing.peerNickname)' vs '\(relationship.peerNickname)'",
category: .session, level: .warning)
SecureLogger.warning("⚠️ Duplicate favorite found for public key \(relationship.peerNoisePublicKey.hexEncodedString()) - nicknames: '\(existing.peerNickname)' vs '\(relationship.peerNickname)'", category: .session)
// Keep the most recent or most complete relationship
if relationship.lastUpdated > existing.lastUpdated ||
@@ -414,7 +404,7 @@ final class FavoritesPersistenceService: ObservableObject {
// Log loaded relationships
// Loaded relationships successfully
} catch {
SecureLogger.log("Failed to load favorites: \(error)", category: .session, level: .error)
SecureLogger.error("Failed to load favorites: \(error)", category: .session)
}
}
}
+3 -3
View File
@@ -198,7 +198,7 @@ final class KeychainManager {
// Delete ALL keychain data for panic mode
func deleteAllKeychainData() -> Bool {
SecureLogger.log("Panic mode - deleting all keychain data", category: .security, level: .warning)
SecureLogger.warning("Panic mode - deleting all keychain data", category: .security)
var totalDeleted = 0
@@ -261,7 +261,7 @@ final class KeychainManager {
let deleteStatus = SecItemDelete(deleteQuery as CFDictionary)
if deleteStatus == errSecSuccess {
totalDeleted += 1
SecureLogger.log("Deleted keychain item: \(account) from \(service)", category: .keychain, level: .info)
SecureLogger.info("Deleted keychain item: \(account) from \(service)", category: .keychain)
}
}
}
@@ -303,7 +303,7 @@ final class KeychainManager {
totalDeleted += 1
}
SecureLogger.log("Panic mode cleanup completed. Total items deleted: \(totalDeleted)", category: .keychain, level: .warning)
SecureLogger.warning("Panic mode cleanup completed. Total items deleted: \(totalDeleted)", category: .keychain)
return totalDeleted > 0
}
@@ -197,8 +197,7 @@ final class LocationChannelManager: NSObject, CLLocationManagerDelegate, Observa
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
// Surface as denied/restricted if relevant; otherwise keep previous state
SecureLogger.log("LocationChannelManager: location error: \(error.localizedDescription)",
category: .session, level: .error)
SecureLogger.error("LocationChannelManager: location error: \(error.localizedDescription)", category: .session)
}
// MARK: - Helpers
+9 -18
View File
@@ -39,40 +39,34 @@ final class MessageRouter {
func sendPrivate(_ content: String, to peerID: String, recipientNickname: String, messageID: String) {
let reachableMesh = mesh.isPeerReachable(peerID)
if reachableMesh {
SecureLogger.log("Routing PM via mesh (reachable) to \(peerID.prefix(8))… id=\(messageID.prefix(8))",
category: .session, level: .debug)
SecureLogger.debug("Routing PM via mesh (reachable) to \(peerID.prefix(8))… id=\(messageID.prefix(8))", category: .session)
// BLEService will initiate a handshake if needed and queue the message
mesh.sendPrivateMessage(content, to: peerID, recipientNickname: recipientNickname, messageID: messageID)
} else if canSendViaNostr(peerID: peerID) {
SecureLogger.log("Routing PM via Nostr to \(peerID.prefix(8))… id=\(messageID.prefix(8))",
category: .session, level: .debug)
SecureLogger.debug("Routing PM via Nostr to \(peerID.prefix(8))… id=\(messageID.prefix(8))", category: .session)
nostr.sendPrivateMessage(content, to: peerID, recipientNickname: recipientNickname, messageID: messageID)
} else {
// Queue for later (when mesh connects or Nostr mapping appears)
if outbox[peerID] == nil { outbox[peerID] = [] }
outbox[peerID]?.append((content, recipientNickname, messageID))
SecureLogger.log("Queued PM for \(peerID.prefix(8))… (no mesh, no Nostr mapping) id=\(messageID.prefix(8))",
category: .session, level: .debug)
SecureLogger.debug("Queued PM for \(peerID.prefix(8))… (no mesh, no Nostr mapping) id=\(messageID.prefix(8))", category: .session)
}
}
func sendReadReceipt(_ receipt: ReadReceipt, to peerID: String) {
// Prefer mesh for reachable peers; BLE will queue if handshake is needed
if mesh.isPeerReachable(peerID) {
SecureLogger.log("Routing READ ack via mesh (reachable) to \(peerID.prefix(8))… id=\(receipt.originalMessageID.prefix(8))",
category: .session, level: .debug)
SecureLogger.debug("Routing READ ack via mesh (reachable) to \(peerID.prefix(8))… id=\(receipt.originalMessageID.prefix(8))", category: .session)
mesh.sendReadReceipt(receipt, to: peerID)
} else {
SecureLogger.log("Routing READ ack via Nostr to \(peerID.prefix(8))… id=\(receipt.originalMessageID.prefix(8))",
category: .session, level: .debug)
SecureLogger.debug("Routing READ ack via Nostr to \(peerID.prefix(8))… id=\(receipt.originalMessageID.prefix(8))", category: .session)
nostr.sendReadReceipt(receipt, to: peerID)
}
}
func sendDeliveryAck(_ messageID: String, to peerID: String) {
if mesh.isPeerReachable(peerID) {
SecureLogger.log("Routing DELIVERED ack via mesh (reachable) to \(peerID.prefix(8))… id=\(messageID.prefix(8))",
category: .session, level: .debug)
SecureLogger.debug("Routing DELIVERED ack via mesh (reachable) to \(peerID.prefix(8))… id=\(messageID.prefix(8))", category: .session)
mesh.sendDeliveryAck(for: messageID, to: peerID)
} else {
nostr.sendDeliveryAck(for: messageID, to: peerID)
@@ -108,18 +102,15 @@ final class MessageRouter {
func flushOutbox(for peerID: String) {
guard let queued = outbox[peerID], !queued.isEmpty else { return }
SecureLogger.log("Flushing outbox for \(peerID.prefix(8))… count=\(queued.count)",
category: .session, level: .debug)
SecureLogger.debug("Flushing outbox for \(peerID.prefix(8))… count=\(queued.count)", category: .session)
var remaining: [(content: String, nickname: String, messageID: String)] = []
// Prefer mesh if connected; else try Nostr if mapping exists
for (content, nickname, messageID) in queued {
if mesh.isPeerReachable(peerID) {
SecureLogger.log("Outbox -> mesh for \(peerID.prefix(8))… id=\(messageID.prefix(8))",
category: .session, level: .debug)
SecureLogger.debug("Outbox -> mesh for \(peerID.prefix(8))… id=\(messageID.prefix(8))", category: .session)
mesh.sendPrivateMessage(content, to: peerID, recipientNickname: nickname, messageID: messageID)
} else if canSendViaNostr(peerID: peerID) {
SecureLogger.log("Outbox -> Nostr for \(peerID.prefix(8))… id=\(messageID.prefix(8))",
category: .session, level: .debug)
SecureLogger.debug("Outbox -> Nostr for \(peerID.prefix(8))… id=\(messageID.prefix(8))", category: .session)
nostr.sendPrivateMessage(content, to: peerID, recipientNickname: nickname, messageID: messageID)
} else {
// Keep unsent items queued
@@ -270,7 +270,7 @@ final class NoiseEncryptionService {
let deletedStatic = KeychainManager.shared.deleteIdentityKey(forKey: "noiseStaticKey")
let deletedSigning = KeychainManager.shared.deleteIdentityKey(forKey: "ed25519SigningKey")
SecureLogger.logKeyOperation("delete", keyType: "identity keys", success: deletedStatic && deletedSigning)
SecureLogger.log("Panic mode activated - identity cleared", category: .security, level: .warning)
SecureLogger.warning("Panic mode activated - identity cleared", category: .security)
// Stop rekey timer
stopRekeyTimer()
}
@@ -573,7 +573,7 @@ final class NoiseEncryptionService {
// Attempt to rekey the session
do {
try sessionManager.initiateRekey(for: peerID)
SecureLogger.log("Key rotation initiated for peer: \(peerID)", category: .security, level: .debug)
SecureLogger.debug("Key rotation initiated for peer: \(peerID)", category: .security)
// Signal that handshake is needed
onHandshakeRequired?(peerID)
+24 -36
View File
@@ -51,31 +51,29 @@ final class NostrTransport: Transport {
Task { @MainActor in
guard let recipientNpub = resolveRecipientNpub(for: peerID) else { return }
guard let senderIdentity = try? NostrIdentityBridge.getCurrentNostrIdentity() else { return }
SecureLogger.log("NostrTransport: preparing PM to \(recipientNpub.prefix(16))… for peerID \(peerID.prefix(8))… id=\(messageID.prefix(8))",
category: .session, level: .debug)
SecureLogger.debug("NostrTransport: preparing PM to \(recipientNpub.prefix(16))… for peerID \(peerID.prefix(8))… id=\(messageID.prefix(8))", category: .session)
// Convert recipient npub -> hex (x-only)
let recipientHex: String
do {
let (hrp, data) = try Bech32.decode(recipientNpub)
guard hrp == "npub" else {
SecureLogger.log("NostrTransport: recipient key not npub (hrp=\(hrp))", category: .session, level: .error)
SecureLogger.error("NostrTransport: recipient key not npub (hrp=\(hrp))", category: .session)
return
}
recipientHex = data.hexEncodedString()
} catch {
SecureLogger.log("NostrTransport: failed to decode npub -> hex: \(error)", category: .session, level: .error)
SecureLogger.error("NostrTransport: failed to decode npub -> hex: \(error)", category: .session)
return
}
guard let embedded = NostrEmbeddedBitChat.encodePMForNostr(content: content, messageID: messageID, recipientPeerID: peerID, senderPeerID: senderPeerID) else {
SecureLogger.log("NostrTransport: failed to embed PM packet", category: .session, level: .error)
SecureLogger.error("NostrTransport: failed to embed PM packet", category: .session)
return
}
guard let event = try? NostrProtocol.createPrivateMessage(content: embedded, recipientPubkey: recipientHex, senderIdentity: senderIdentity) else {
SecureLogger.log("NostrTransport: failed to build Nostr event for PM", category: .session, level: .error)
SecureLogger.error("NostrTransport: failed to build Nostr event for PM", category: .session)
return
}
SecureLogger.log("NostrTransport: sending PM giftWrap id=\(event.id.prefix(16))",
category: .session, level: .debug)
SecureLogger.debug("NostrTransport: sending PM giftWrap id=\(event.id.prefix(16))", category: .session)
NostrRelayManager.shared.sendEvent(event)
}
}
@@ -99,8 +97,7 @@ final class NostrTransport: Transport {
Task { @MainActor in
guard let recipientNpub = resolveRecipientNpub(for: item.peerID) else { scheduleNextReadAck(); return }
guard let senderIdentity = try? NostrIdentityBridge.getCurrentNostrIdentity() else { scheduleNextReadAck(); return }
SecureLogger.log("NostrTransport: preparing READ ack for id=\(item.receipt.originalMessageID.prefix(8))… to \(recipientNpub.prefix(16))",
category: .session, level: .debug)
SecureLogger.debug("NostrTransport: preparing READ ack for id=\(item.receipt.originalMessageID.prefix(8))… to \(recipientNpub.prefix(16))", category: .session)
// Convert recipient npub -> hex
let recipientHex: String
do {
@@ -109,15 +106,14 @@ final class NostrTransport: Transport {
recipientHex = data.hexEncodedString()
} catch { scheduleNextReadAck(); return }
guard let ack = NostrEmbeddedBitChat.encodeAckForNostr(type: .readReceipt, messageID: item.receipt.originalMessageID, recipientPeerID: item.peerID, senderPeerID: senderPeerID) else {
SecureLogger.log("NostrTransport: failed to embed READ ack", category: .session, level: .error)
SecureLogger.error("NostrTransport: failed to embed READ ack", category: .session)
scheduleNextReadAck(); return
}
guard let event = try? NostrProtocol.createPrivateMessage(content: ack, recipientPubkey: recipientHex, senderIdentity: senderIdentity) else {
SecureLogger.log("NostrTransport: failed to build Nostr event for READ ack", category: .session, level: .error)
SecureLogger.error("NostrTransport: failed to build Nostr event for READ ack", category: .session)
scheduleNextReadAck(); return
}
SecureLogger.log("NostrTransport: sending READ ack giftWrap id=\(event.id.prefix(16))",
category: .session, level: .debug)
SecureLogger.debug("NostrTransport: sending READ ack giftWrap id=\(event.id.prefix(16))", category: .session)
NostrRelayManager.shared.sendEvent(event)
scheduleNextReadAck()
}
@@ -136,8 +132,7 @@ final class NostrTransport: Transport {
guard let recipientNpub = resolveRecipientNpub(for: peerID) else { return }
guard let senderIdentity = try? NostrIdentityBridge.getCurrentNostrIdentity() else { return }
let content = isFavorite ? "[FAVORITED]:\(senderIdentity.npub)" : "[UNFAVORITED]:\(senderIdentity.npub)"
SecureLogger.log("NostrTransport: preparing FAVORITE(\(isFavorite)) to \(recipientNpub.prefix(16))",
category: .session, level: .debug)
SecureLogger.debug("NostrTransport: preparing FAVORITE(\(isFavorite)) to \(recipientNpub.prefix(16))", category: .session)
// Convert recipient npub -> hex
let recipientHex: String
do {
@@ -146,15 +141,14 @@ final class NostrTransport: Transport {
recipientHex = data.hexEncodedString()
} catch { return }
guard let embedded = NostrEmbeddedBitChat.encodePMForNostr(content: content, messageID: UUID().uuidString, recipientPeerID: peerID, senderPeerID: senderPeerID) else {
SecureLogger.log("NostrTransport: failed to embed favorite notification", category: .session, level: .error)
SecureLogger.error("NostrTransport: failed to embed favorite notification", category: .session)
return
}
guard let event = try? NostrProtocol.createPrivateMessage(content: embedded, recipientPubkey: recipientHex, senderIdentity: senderIdentity) else {
SecureLogger.log("NostrTransport: failed to build Nostr event for favorite notification", category: .session, level: .error)
SecureLogger.error("NostrTransport: failed to build Nostr event for favorite notification", category: .session)
return
}
SecureLogger.log("NostrTransport: sending favorite giftWrap id=\(event.id.prefix(16))",
category: .session, level: .debug)
SecureLogger.debug("NostrTransport: sending favorite giftWrap id=\(event.id.prefix(16))", category: .session)
NostrRelayManager.shared.sendEvent(event)
}
}
@@ -180,8 +174,7 @@ final class NostrTransport: Transport {
Task { @MainActor in
guard let recipientNpub = resolveRecipientNpub(for: peerID) else { return }
guard let senderIdentity = try? NostrIdentityBridge.getCurrentNostrIdentity() else { return }
SecureLogger.log("NostrTransport: preparing DELIVERED ack for id=\(messageID.prefix(8))… to \(recipientNpub.prefix(16))",
category: .session, level: .debug)
SecureLogger.debug("NostrTransport: preparing DELIVERED ack for id=\(messageID.prefix(8))… to \(recipientNpub.prefix(16))", category: .session)
let recipientHex: String
do {
let (hrp, data) = try Bech32.decode(recipientNpub)
@@ -189,15 +182,14 @@ final class NostrTransport: Transport {
recipientHex = data.hexEncodedString()
} catch { return }
guard let ack = NostrEmbeddedBitChat.encodeAckForNostr(type: .delivered, messageID: messageID, recipientPeerID: peerID, senderPeerID: senderPeerID) else {
SecureLogger.log("NostrTransport: failed to embed DELIVERED ack", category: .session, level: .error)
SecureLogger.error("NostrTransport: failed to embed DELIVERED ack", category: .session)
return
}
guard let event = try? NostrProtocol.createPrivateMessage(content: ack, recipientPubkey: recipientHex, senderIdentity: senderIdentity) else {
SecureLogger.log("NostrTransport: failed to build Nostr event for DELIVERED ack", category: .session, level: .error)
SecureLogger.error("NostrTransport: failed to build Nostr event for DELIVERED ack", category: .session)
return
}
SecureLogger.log("NostrTransport: sending DELIVERED ack giftWrap id=\(event.id.prefix(16))",
category: .session, level: .debug)
SecureLogger.debug("NostrTransport: sending DELIVERED ack giftWrap id=\(event.id.prefix(16))", category: .session)
NostrRelayManager.shared.sendEvent(event)
}
}
@@ -205,8 +197,7 @@ final class NostrTransport: Transport {
// MARK: - Geohash ACK helpers
func sendDeliveryAckGeohash(for messageID: String, toRecipientHex recipientHex: String, from identity: NostrIdentity) {
Task { @MainActor in
SecureLogger.log("GeoDM: send DELIVERED -> recip=\(recipientHex.prefix(8))… mid=\(messageID.prefix(8))… from=\(identity.publicKeyHex.prefix(8))",
category: .session, level: .debug)
SecureLogger.debug("GeoDM: send DELIVERED -> recip=\(recipientHex.prefix(8))… mid=\(messageID.prefix(8))… from=\(identity.publicKeyHex.prefix(8))", category: .session)
guard let embedded = NostrEmbeddedBitChat.encodeAckForNostrNoRecipient(type: .delivered, messageID: messageID, senderPeerID: senderPeerID) else { return }
guard let event = try? NostrProtocol.createPrivateMessage(content: embedded, recipientPubkey: recipientHex, senderIdentity: identity) else { return }
NostrRelayManager.registerPendingGiftWrap(id: event.id)
@@ -216,8 +207,7 @@ final class NostrTransport: Transport {
func sendReadReceiptGeohash(_ messageID: String, toRecipientHex recipientHex: String, from identity: NostrIdentity) {
Task { @MainActor in
SecureLogger.log("GeoDM: send READ -> recip=\(recipientHex.prefix(8))… mid=\(messageID.prefix(8))… from=\(identity.publicKeyHex.prefix(8))",
category: .session, level: .debug)
SecureLogger.debug("GeoDM: send READ -> recip=\(recipientHex.prefix(8))… mid=\(messageID.prefix(8))… from=\(identity.publicKeyHex.prefix(8))", category: .session)
guard let embedded = NostrEmbeddedBitChat.encodeAckForNostrNoRecipient(type: .readReceipt, messageID: messageID, senderPeerID: senderPeerID) else { return }
guard let event = try? NostrProtocol.createPrivateMessage(content: embedded, recipientPubkey: recipientHex, senderIdentity: identity) else { return }
NostrRelayManager.registerPendingGiftWrap(id: event.id)
@@ -229,19 +219,17 @@ final class NostrTransport: Transport {
func sendPrivateMessageGeohash(content: String, toRecipientHex recipientHex: String, from identity: NostrIdentity, messageID: String) {
Task { @MainActor in
guard !recipientHex.isEmpty else { return }
SecureLogger.log("GeoDM: send PM -> recip=\(recipientHex.prefix(8))… mid=\(messageID.prefix(8))… from=\(identity.publicKeyHex.prefix(8))",
category: .session, level: .debug)
SecureLogger.debug("GeoDM: send PM -> recip=\(recipientHex.prefix(8))… mid=\(messageID.prefix(8))… from=\(identity.publicKeyHex.prefix(8))", category: .session)
// Build embedded BitChat packet without recipient peer ID
guard let embedded = NostrEmbeddedBitChat.encodePMForNostrNoRecipient(content: content, messageID: messageID, senderPeerID: senderPeerID) else {
SecureLogger.log("NostrTransport: failed to embed geohash PM packet", category: .session, level: .error)
SecureLogger.error("NostrTransport: failed to embed geohash PM packet", category: .session)
return
}
guard let event = try? NostrProtocol.createPrivateMessage(content: embedded, recipientPubkey: recipientHex, senderIdentity: identity) else {
SecureLogger.log("NostrTransport: failed to build Nostr event for geohash PM", category: .session, level: .error)
SecureLogger.error("NostrTransport: failed to build Nostr event for geohash PM", category: .session)
return
}
SecureLogger.log("NostrTransport: sending geohash PM giftWrap id=\(event.id.prefix(16))",
category: .session, level: .debug)
SecureLogger.debug("NostrTransport: sending geohash PM giftWrap id=\(event.id.prefix(16))", category: .session)
NostrRelayManager.registerPendingGiftWrap(id: event.id)
NostrRelayManager.shared.sendEvent(event)
}
+1 -2
View File
@@ -228,8 +228,7 @@ final class PrivateChatManager: ObservableObject {
// Route via MessageRouter to avoid handshakeRequired spam when session isn't established
if let router = messageRouter {
SecureLogger.log("PrivateChatManager: sending READ ack for \(message.id.prefix(8))… to \(senderPeerID.prefix(8))… via router",
category: .session, level: .debug)
SecureLogger.debug("PrivateChatManager: sending READ ack for \(message.id.prefix(8))… to \(senderPeerID.prefix(8))… via router", category: .session)
Task { @MainActor in
router.sendReadReceipt(receipt, to: senderPeerID)
}
+13 -13
View File
@@ -189,7 +189,7 @@ final class TorManager: ObservableObject {
var started = false
// If already running (per C glue), treat as started
if tor_host_is_running() != 0 {
SecureLogger.log("TorManager: embed reports already running", category: .session, level: .info)
SecureLogger.info("TorManager: embed reports already running", category: .session)
return true
}
dir.withCString { dptr in
@@ -198,9 +198,9 @@ final class TorManager: ObservableObject {
let rc = tor_host_start(dptr, sptr, cptr, 1)
started = (rc == 0)
if rc != 0 {
SecureLogger.log("TorManager: tor_host_start failed rc=\(rc)", category: .session, level: .error)
SecureLogger.error("TorManager: tor_host_start failed rc=\(rc)", category: .session)
} else {
SecureLogger.log("TorManager: tor_host_start OK (\(socks), control \(control))", category: .session, level: .info)
SecureLogger.info("TorManager: tor_host_start OK (\(socks), control \(control))", category: .session)
}
}
}
@@ -215,10 +215,10 @@ final class TorManager: ObservableObject {
await MainActor.run {
self.socksReady = ready
if ready {
SecureLogger.log("TorManager: SOCKS ready at \(self.socksHost):\(self.socksPort) [embed]", category: .session, level: .info)
SecureLogger.info("TorManager: SOCKS ready at \(self.socksHost):\(self.socksPort) [embed]", category: .session)
} else {
self.lastError = NSError(domain: "TorManager", code: -14, userInfo: [NSLocalizedDescriptionKey: "Tor SOCKS not reachable after embed start"])
SecureLogger.log("TorManager: SOCKS not reachable (timeout) [embed]", category: .session, level: .error)
SecureLogger.error("TorManager: SOCKS not reachable (timeout) [embed]", category: .session)
}
}
}
@@ -282,13 +282,13 @@ final class TorManager: ObservableObject {
/// Returns true if the attempt started and port probing was scheduled.
private func startTorViaDlopen() -> Bool {
guard let fwURL = frameworkBinaryURL() else {
SecureLogger.log("TorManager: no embedded tor framework found", category: .session, level: .warning)
SecureLogger.warning("TorManager: no embedded tor framework found", category: .session)
return false
}
// Load the library
let mode = RTLD_NOW | RTLD_LOCAL
SecureLogger.log("TorManager: dlopen(\(fwURL.lastPathComponent))…", category: .session, level: .info)
SecureLogger.info("TorManager: dlopen(\(fwURL.lastPathComponent))…", category: .session)
guard let handle = dlopen(fwURL.path, mode) else {
let err = String(cString: dlerror())
self.lastError = NSError(domain: "TorManager", code: -10, userInfo: [NSLocalizedDescriptionKey: "dlopen failed: \(err)"])
@@ -314,7 +314,7 @@ final class TorManager: ObservableObject {
argv.append(contentsOf: ["-f", torrc])
}
// Run Tor on a background thread to avoid blocking the main actor
SecureLogger.log("TorManager: launching tor_main with torrc", category: .session, level: .info)
SecureLogger.info("TorManager: launching tor_main with torrc", category: .session)
let argc = Int32(argv.count)
DispatchQueue.global(qos: .utility).async {
// Build stable C argv in this thread
@@ -339,9 +339,9 @@ final class TorManager: ObservableObject {
self.socksReady = ready
if !ready {
self.lastError = NSError(domain: "TorManager", code: -12, userInfo: [NSLocalizedDescriptionKey: "Tor SOCKS not reachable after dlopen start"])
SecureLogger.log("TorManager: SOCKS not reachable (timeout)", category: .session, level: .error)
SecureLogger.error("TorManager: SOCKS not reachable (timeout)", category: .session)
} else {
SecureLogger.log("TorManager: SOCKS ready at \(self.socksHost):\(self.socksPort)", category: .session, level: .info)
SecureLogger.info("TorManager: SOCKS ready at \(self.socksHost):\(self.socksPort)", category: .session)
}
// isStarting will be cleared when bootstrap reaches 100%
}
@@ -385,7 +385,7 @@ final class TorManager: ObservableObject {
var argv: [String] = ["tor"]
if let torrc = torrcURL()?.path { argv.append(contentsOf: ["-f", torrc]) }
SecureLogger.log("TorManager: starting tor_main (static)", category: .session, level: .info)
SecureLogger.info("TorManager: starting tor_main (static)", category: .session)
let argc = Int32(argv.count)
DispatchQueue.global(qos: .utility).async {
// Build stable C argv in this thread
@@ -409,10 +409,10 @@ final class TorManager: ObservableObject {
await MainActor.run {
self.socksReady = ready
if ready {
SecureLogger.log("TorManager: SOCKS ready at \(self.socksHost):\(self.socksPort)", category: .session, level: .info)
SecureLogger.info("TorManager: SOCKS ready at \(self.socksHost):\(self.socksPort)", category: .session)
} else {
self.lastError = NSError(domain: "TorManager", code: -13, userInfo: [NSLocalizedDescriptionKey: "Tor SOCKS not reachable after static start"])
SecureLogger.log("TorManager: SOCKS not reachable (timeout)", category: .session, level: .error)
SecureLogger.error("TorManager: SOCKS not reachable (timeout)", category: .session)
}
// isStarting will be cleared when bootstrap reaches 100%
}
+5 -13
View File
@@ -203,11 +203,7 @@ final class UnifiedPeerService: ObservableObject, TransportPeerEventsDelegate {
if let favorite = favoriteByNickname,
let noiseKey = peerInfo.noisePublicKey {
SecureLogger.log(
"🔄 Found favorite for '\(peerInfo.nickname)' by nickname, updating noise key",
category: .session,
level: .debug
)
SecureLogger.debug("🔄 Found favorite for '\(peerInfo.nickname)' by nickname, updating noise key", category: .session)
// Update the favorite's key in persistence
favoritesService.updateNoisePublicKey(
@@ -282,8 +278,7 @@ final class UnifiedPeerService: ObservableObject, TransportPeerEventsDelegate {
/// Toggle favorite status
func toggleFavorite(_ peerID: String) {
guard let peer = getPeer(by: peerID) else {
SecureLogger.log("⚠️ Cannot toggle favorite - peer not found: \(peerID)",
category: .session, level: .warning)
SecureLogger.warning("⚠️ Cannot toggle favorite - peer not found: \(peerID)", category: .session)
return
}
@@ -293,15 +288,13 @@ final class UnifiedPeerService: ObservableObject, TransportPeerEventsDelegate {
var actualNickname = peer.nickname
// Debug logging to understand the issue
SecureLogger.log("🔍 Toggle favorite - peer.nickname: '\(peer.nickname)', peer.displayName: '\(peer.displayName)', peerID: \(peerID)",
category: .session, level: .debug)
SecureLogger.debug("🔍 Toggle favorite - peer.nickname: '\(peer.nickname)', peer.displayName: '\(peer.displayName)', peerID: \(peerID)", category: .session)
if actualNickname.isEmpty {
// Try to get from mesh service's current peer list
if let meshPeerNickname = meshService.peerNickname(peerID: peerID) {
actualNickname = meshPeerNickname
SecureLogger.log("🔍 Got nickname from mesh service: '\(actualNickname)'",
category: .session, level: .debug)
SecureLogger.debug("🔍 Got nickname from mesh service: '\(actualNickname)'", category: .session)
}
}
@@ -328,8 +321,7 @@ final class UnifiedPeerService: ObservableObject, TransportPeerEventsDelegate {
}
// Log the final nickname being saved
SecureLogger.log("⭐️ Toggled favorite for '\(finalNickname)' (peerID: \(peerID), was: \(wasFavorite), now: \(!wasFavorite))",
category: .session, level: .debug)
SecureLogger.debug("⭐️ Toggled favorite for '\(finalNickname)' (peerID: \(peerID), was: \(wasFavorite), now: \(!wasFavorite))", category: .session)
// Send favorite notification to the peer via router (mesh or Nostr)
if let router = messageRouter {