Make logging categories static properties of OSLog

So we can use `.<category name>` to simplify the code.

Search/Replace Strategy:
Search text: `category: SecureLogger.`
Replace text: `category: .`
This commit is contained in:
islam
2025-09-11 19:02:32 +01:00
parent ee16ff5ff4
commit 5ca9222fc2
21 changed files with 354 additions and 345 deletions
+87 -87
View File
@@ -463,7 +463,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
UserDefaults.standard.set(data, forKey: "sentReadReceipts")
} else {
SecureLogger.log("❌ Failed to encode read receipts for persistence",
category: SecureLogger.session, level: .error)
category: .session, level: .error)
}
}
}
@@ -562,11 +562,11 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
// Wait for Tor readiness before Nostr init
let ready = await TorManager.shared.awaitReady(timeout: 60)
guard ready else {
SecureLogger.log("Nostr init skipped: Tor not ready", category: SecureLogger.session, level: .error)
SecureLogger.log("Nostr init skipped: Tor not ready", category: .session, level: .error)
return
}
nostrRelayManager = NostrRelayManager.shared
SecureLogger.log("Initializing Nostr relay connections", category: SecureLogger.session, level: .debug)
SecureLogger.log("Initializing Nostr relay connections", category: .session, level: .debug)
// Connect is managed centrally on scene activation; avoid duplicate connects here
// Attempt to flush any queued outbox after Nostr comes online
@@ -597,7 +597,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
uniquePeers[peer.id] = peer
} else {
SecureLogger.log("⚠️ Duplicate peer ID detected: \(peer.id) (\(peer.displayName))",
category: SecureLogger.session, level: .warning)
category: .session, level: .warning)
}
}
self.peerIndex = uniquePeers
@@ -1036,10 +1036,10 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
self.privateChats[convKey]?[idx].deliveryStatus = .delivered(to: self.displayNameForNostrPubkey(senderPubkey), at: Date())
self.objectWillChange.send()
SecureLogger.log("GeoDM: recv DELIVERED for mid=\(messageID.prefix(8))… from=\(senderPubkey.prefix(8))",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
} else {
SecureLogger.log("GeoDM: delivered ack for unknown mid=\(messageID.prefix(8))… conv=\(convKey)",
category: SecureLogger.session, level: .warning)
category: .session, level: .warning)
}
}
case .readReceipt:
@@ -1048,10 +1048,10 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
self.privateChats[convKey]?[idx].deliveryStatus = .read(by: self.displayNameForNostrPubkey(senderPubkey), at: Date())
self.objectWillChange.send()
SecureLogger.log("GeoDM: recv READ for mid=\(messageID.prefix(8))… from=\(senderPubkey.prefix(8))",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
} else {
SecureLogger.log("GeoDM: read ack for unknown mid=\(messageID.prefix(8))… conv=\(convKey)",
category: SecureLogger.session, level: .warning)
category: .session, level: .warning)
}
}
case .verifyChallenge, .verifyResponse:
@@ -1464,14 +1464,14 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
count: TransportConfig.nostrGeoRelayCount
)
if targetRelays.isEmpty {
SecureLogger.log("Geo: no geohash relays available for \(ch.geohash); not sending", category: SecureLogger.session, level: .warning)
SecureLogger.log("Geo: no geohash relays available for \(ch.geohash); not sending", category: .session, level: .warning)
} else {
NostrRelayManager.shared.sendEvent(event, to: targetRelays)
}
// Track ourselves as active participant
self.recordGeoParticipant(pubkeyHex: identity.publicKeyHex)
SecureLogger.log("GeoTeleport: sent geo message pub=\(identity.publicKeyHex.prefix(8))… teleported=\(LocationChannelManager.shared.teleported)",
category: SecureLogger.session, level: .debug)
category: .session, level: .debug)
// If we tagged this as teleported, also mark our pubkey in teleportedGeo for UI
// Only when not in our regional set (and regional list is known)
let hasRegional = !LocationChannelManager.shared.availableChannels.isEmpty
@@ -1480,10 +1480,10 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
let key = identity.publicKeyHex.lowercased()
self.teleportedGeo = self.teleportedGeo.union([key])
SecureLogger.log("GeoTeleport: mark self teleported key=\(key.prefix(8))… total=\(self.teleportedGeo.count)",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
}
} catch {
SecureLogger.log("❌ Failed to send geohash message: \(error)", category: SecureLogger.session, level: .error)
SecureLogger.log("❌ Failed to send geohash message: \(error)", category: .session, level: .error)
self.addSystemMessage("failed to send to location channel")
}
}
@@ -1510,7 +1510,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
// Debug: log if any empty messages are present
let emptyMesh = messages.filter { $0.content.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty }.count
if emptyMesh > 0 {
SecureLogger.log("RenderGuard: mesh timeline contains \(emptyMesh) empty messages", category: SecureLogger.session, level: .debug)
SecureLogger.log("RenderGuard: mesh timeline contains \(emptyMesh) empty messages", category: .session, level: .debug)
}
stopGeoParticipantsTimer()
geohashPeople = []
@@ -1537,7 +1537,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
// Debug: log if any empty messages are present post-sanitize
let emptyGeo = messages.filter { $0.content.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty }.count
if emptyGeo > 0 {
SecureLogger.log("RenderGuard: geohash \(ch.geohash) timeline has \(emptyGeo) empty messages after sanitize", category: SecureLogger.session, level: .debug)
SecureLogger.log("RenderGuard: geohash \(ch.geohash) timeline has \(emptyGeo) empty messages after sanitize", category: .session, level: .debug)
}
}
// If switching to a location channel, flush any pending geohash-only system messages
@@ -1570,7 +1570,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
if LocationChannelManager.shared.teleported && hasRegional && !inRegional {
teleportedGeo = teleportedGeo.union([key])
SecureLogger.log("GeoTeleport: channel switch mark self teleported key=\(key.prefix(8))… total=\(teleportedGeo.count)",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
} else {
teleportedGeo.remove(key)
}
@@ -1594,7 +1594,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
// Log incoming tags for diagnostics
let tagSummary = event.tags.map { "[" + $0.joined(separator: ",") + "]" }.joined(separator: ",")
SecureLogger.log("GeoTeleport: recv pub=\(event.pubkey.prefix(8))… tags=\(tagSummary)",
category: SecureLogger.session, level: .debug)
category: .session, level: .debug)
// Track teleport tag for participants only our format ["t", "teleport"]
let hasTeleportTag: Bool = event.tags.contains(where: { tag in
tag.count >= 2 && tag[0].lowercased() == "t" && tag[1].lowercased() == "teleport"
@@ -1612,7 +1612,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
Task { @MainActor in
self.teleportedGeo = self.teleportedGeo.union([key])
SecureLogger.log("GeoTeleport: mark peer teleported key=\(key.prefix(8))… total=\(self.teleportedGeo.count)",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
}
}
}
@@ -1677,7 +1677,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
// Log GeoDM subscribe only when Tor is ready to avoid early noise
if TorManager.shared.isReady {
SecureLogger.log("GeoDM: subscribing DMs pub=\(id.publicKeyHex.prefix(8))… sub=\(dmSub)",
category: SecureLogger.session, level: .debug)
category: .session, level: .debug)
}
let dmFilter = NostrFilter.giftWrapsFor(pubkey: id.publicKeyHex, since: Date().addingTimeInterval(-TransportConfig.nostrDMSubscribeLookbackSeconds))
NostrRelayManager.shared.subscribe(filter: dmFilter, id: dmSub) { [weak self] giftWrap in
@@ -1688,11 +1688,11 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
// Decrypt with per-geohash identity
guard let (content, senderPubkey, rumorTs) = try? NostrProtocol.decryptPrivateMessage(giftWrap: giftWrap, recipientIdentity: id) else {
SecureLogger.log("GeoDM: failed decrypt giftWrap id=\(giftWrap.id.prefix(8))",
category: SecureLogger.session, level: .warning)
category: .session, level: .warning)
return
}
SecureLogger.log("GeoDM: decrypted gift-wrap id=\(giftWrap.id.prefix(16))... from=\(senderPubkey.prefix(8))...",
category: SecureLogger.session, level: .debug)
category: .session, level: .debug)
guard content.hasPrefix("bitchat1:") else { return }
guard let packetData = Self.base64URLDecode(String(content.dropFirst("bitchat1:".count))),
let packet = BitchatPacket.from(packetData) else { return }
@@ -1706,7 +1706,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
guard let pm = PrivateMessagePacket.decode(from: noisePayload.data) else { return }
let messageId = pm.messageID
SecureLogger.log("GeoDM: recv PM <- sender=\(senderPubkey.prefix(8))… mid=\(messageId.prefix(8))",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
// Send delivery ACK immediately (even if duplicate), once per messageID
if !self.sentGeoDeliveryAcks.contains(messageId) {
let nostrTransport = NostrTransport()
@@ -1770,10 +1770,10 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
self.privateChats[convKey]?[idx].deliveryStatus = .delivered(to: self.displayNameForNostrPubkey(senderPubkey), at: Date())
self.objectWillChange.send()
SecureLogger.log("GeoDM: recv DELIVERED for mid=\(messageID.prefix(8))… from=\(senderPubkey.prefix(8))",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
} else {
SecureLogger.log("GeoDM: delivered ack for unknown mid=\(messageID.prefix(8))… conv=\(convKey)",
category: SecureLogger.session, level: .warning)
category: .session, level: .warning)
}
}
case .readReceipt:
@@ -1782,10 +1782,10 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
self.privateChats[convKey]?[idx].deliveryStatus = .read(by: self.displayNameForNostrPubkey(senderPubkey), at: Date())
self.objectWillChange.send()
SecureLogger.log("GeoDM: recv READ for mid=\(messageID.prefix(8))… from=\(senderPubkey.prefix(8))",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
} else {
SecureLogger.log("GeoDM: read ack for unknown mid=\(messageID.prefix(8))… conv=\(convKey)",
category: SecureLogger.session, level: .warning)
category: .session, level: .warning)
}
}
default:
@@ -2153,7 +2153,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
return
}
SecureLogger.log("GeoDM: local send mid=\(messageID.prefix(8))… to=\(recipientHex.prefix(8))… conv=\(peerID)",
category: SecureLogger.session, level: .debug)
category: .session, level: .debug)
let nostrTransport = NostrTransport()
nostrTransport.senderPeerID = meshService.myPeerID
nostrTransport.sendPrivateMessageGeohash(content: content, toRecipientHex: recipientHex, from: id, messageID: messageID)
@@ -2474,7 +2474,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
if hadUnreadTemp {
unreadPrivateMessages.insert(peerID)
SecureLogger.log("📬 Transferred unread status from temp peer IDs to \(peerID)",
category: SecureLogger.session, level: .debug)
category: .session, level: .debug)
}
if consolidatedCount > 0 {
@@ -2482,7 +2482,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
privateChats[peerID]?.sort { $0.timestamp < $1.timestamp }
SecureLogger.log("📥 Consolidated \(consolidatedCount) Nostr messages from temporary peer IDs to \(peerNickname)",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
}
}
@@ -2497,7 +2497,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
}
} else {
SecureLogger.log("GeoDM: skipping mesh handshake for virtual peerID=\(peerID)",
category: SecureLogger.session, level: .debug)
category: .session, level: .debug)
}
// Delegate to private chat manager but add already-acked messages first
@@ -2578,7 +2578,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
guard let receipt = notification.userInfo?["receipt"] as? ReadReceipt else { return }
SecureLogger.log("📖 Handling read receipt for message \(receipt.originalMessageID) from Nostr",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
// Process the read receipt through the same flow as Bluetooth read receipts
didReceiveReadReceipt(receipt)
@@ -2604,7 +2604,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
// If we have a private chat open with the old peer ID, update it to the new one
if selectedPrivateChatPeer == oldPeerID {
SecureLogger.log("📱 Updating private chat peer ID due to key change: \(oldPeerID) -> \(newPeerID)",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
// Transfer private chat messages to new peer ID
if let messages = privateChats[oldPeerID] {
@@ -2636,7 +2636,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
// Even if the chat isn't open, migrate any existing private chat data
if let messages = privateChats[oldPeerID] {
SecureLogger.log("📱 Migrating private chat messages from \(oldPeerID) to \(newPeerID)",
category: SecureLogger.session, level: .debug)
category: .session, level: .debug)
var chats = privateChats
chats[newPeerID] = messages
chats.removeValue(forKey: oldPeerID)
@@ -2742,7 +2742,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
messageRouter.sendPrivate(screenshotMessage, to: peerID, recipientNickname: peerNickname, messageID: UUID().uuidString)
default:
// Don't send screenshot notification if no session exists
SecureLogger.log("Skipping screenshot notification to \(peerID) - no established session", category: SecureLogger.security, level: .debug)
SecureLogger.log("Skipping screenshot notification to \(peerID) - no established session", category: .security, level: .debug)
}
}
@@ -2783,14 +2783,14 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
)
let targetRelays = GeoRelayDirectory.shared.closestRelays(toGeohash: ch.geohash, count: 5)
if targetRelays.isEmpty {
SecureLogger.log("Geo: no geohash relays available for \(ch.geohash); not sending", category: SecureLogger.session, level: .warning)
SecureLogger.log("Geo: no geohash relays available for \(ch.geohash); not sending", category: .session, level: .warning)
} else {
NostrRelayManager.shared.sendEvent(event, to: targetRelays)
}
// Track ourselves as active participant
self.recordGeoParticipant(pubkeyHex: identity.publicKeyHex)
} catch {
SecureLogger.log("❌ Failed to send geohash screenshot message: \(error)", category: SecureLogger.session, level: .error)
SecureLogger.log("❌ Failed to send geohash screenshot message: \(error)", category: .session, level: .error)
self.addSystemMessage("failed to send to location channel")
}
}
@@ -2849,7 +2849,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
for (currentPeerID, currentNickname) in meshService.getPeerNicknames() {
if currentNickname == peerNickname {
SecureLogger.log("📖 Resolved updated peer ID for read receipt: \(peerID) -> \(currentPeerID)",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
actualPeerID = currentPeerID
break
}
@@ -2878,7 +2878,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
for message in messages where message.senderPeerID == peerID && !message.isRelay {
if !sentReadReceipts.contains(message.id) {
SecureLogger.log("GeoDM: sending READ for mid=\(message.id.prefix(8))… to=\(recipientHex.prefix(8))",
category: SecureLogger.session, level: .debug)
category: .session, level: .debug)
let nostrTransport = NostrTransport()
nostrTransport.senderPeerID = meshService.myPeerID
nostrTransport.sendReadReceiptGeohash(message.id, toRecipientHex: recipientHex, from: id)
@@ -4322,14 +4322,14 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
verifiedFingerprints = SecureIdentityStateManager.shared.getVerifiedFingerprints()
// Log snapshot for debugging persistence
let sample = Array(verifiedFingerprints.prefix(TransportConfig.uiFingerprintSampleCount)).map { $0.prefix(8) }.joined(separator: ", ")
SecureLogger.log("🔐 Verified loaded: \(verifiedFingerprints.count) [\(sample)]", category: SecureLogger.security, level: .info)
SecureLogger.log("🔐 Verified loaded: \(verifiedFingerprints.count) [\(sample)]", category: .security, level: .info)
// Also log any offline favorites and whether we consider them verified
let offlineFavorites = unifiedPeerService.favorites.filter { !$0.isConnected }
for fav in offlineFavorites {
let fp = unifiedPeerService.getFingerprint(for: fav.id)
let isVer = fp.flatMap { verifiedFingerprints.contains($0) } ?? false
let fpShort = fp?.prefix(8) ?? "nil"
SecureLogger.log("⭐️ Favorite offline: \(fav.nickname) fp=\(fpShort) verified=\(isVer)", category: SecureLogger.security, level: .info)
SecureLogger.log("⭐️ Favorite offline: \(fav.nickname) fp=\(fpShort) verified=\(isVer)", category: .security, level: .info)
}
// Invalidate cached encryption statuses so offline favorites can show verified badges immediately
invalidateEncryptionCache()
@@ -4345,7 +4345,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
DispatchQueue.main.async {
guard let self = self else { return }
SecureLogger.log("🔐 Authenticated: \(peerID)", category: SecureLogger.security, level: .debug)
SecureLogger.log("🔐 Authenticated: \(peerID)", category: .security, level: .debug)
// Update encryption status
if self.verifiedFingerprints.contains(fingerprint) {
@@ -4365,7 +4365,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
let stable = keyData.hexEncodedString()
self.shortIDToNoiseKey[peerID] = stable
SecureLogger.log("🗺️ Mapped short peerID to Noise key for header continuity: \(peerID) -> \(stable.prefix(8))",
category: SecureLogger.session, level: .debug)
category: .session, level: .debug)
}
// If a QR verification is pending but not sent yet, send it now that session is authenticated
@@ -4373,7 +4373,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
self.meshService.sendVerifyChallenge(to: peerID, noiseKeyHex: pending.noiseKeyHex, nonceA: pending.nonceA)
pending.sent = true
self.pendingQRVerifications[peerID] = pending
SecureLogger.log("📤 Sent deferred verify challenge to \(peerID) after handshake", category: SecureLogger.security, level: .debug)
SecureLogger.log("📤 Sent deferred verify challenge to \(peerID) after handshake", category: .security, level: .debug)
}
// Schedule UI update
@@ -4519,7 +4519,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
pendingQRVerifications.removeValue(forKey: peerID)
if let fp = getFingerprint(for: peerID) {
let short = fp.prefix(8)
SecureLogger.log("🔐 Marking verified fingerprint: \(short)", category: SecureLogger.security, level: .info)
SecureLogger.log("🔐 Marking verified fingerprint: \(short)", category: .security, level: .info)
SecureIdentityStateManager.shared.setVerified(fingerprint: fp, verified: true)
SecureIdentityStateManager.shared.forceSave()
verifiedFingerprints.insert(fp)
@@ -4605,7 +4605,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
// MARK: - Peer Connection Events
func didConnectToPeer(_ peerID: String) {
SecureLogger.log("🤝 Peer connected: \(peerID)", category: SecureLogger.session, level: .debug)
SecureLogger.log("🤝 Peer connected: \(peerID)", category: .session, level: .debug)
// Handle all main actor work async
Task { @MainActor in
@@ -4623,7 +4623,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
try? await Task.sleep(nanoseconds: TransportConfig.uiAsyncMediumSleepNs) // 0.5 seconds
meshService.sendFavoriteNotification(to: peerID, isFavorite: true)
SecureLogger.log("📤 Resent favorite notification to reconnected peer \(peerID)",
category: SecureLogger.session, level: .debug)
category: .session, level: .debug)
}
// Force UI refresh
@@ -4643,7 +4643,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
}
func didDisconnectFromPeer(_ peerID: String) {
SecureLogger.log("👋 Peer disconnected: \(peerID)", category: SecureLogger.session, level: .debug)
SecureLogger.log("👋 Peer disconnected: \(peerID)", category: .session, level: .debug)
// Remove ephemeral session from identity manager
SecureIdentityStateManager.shared.removeEphemeralSession(peerID: peerID)
@@ -4739,7 +4739,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
self.recentlySeenPeers = currentPeerSet
NotificationService.shared.sendNetworkAvailableNotification(peerCount: meshPeers.count)
SecureLogger.log("👥 Sent bitchatters nearby notification for \(meshPeers.count) mesh peers",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
}
} else {
// No peers immediately reset to allow next rising-edge to notify
@@ -4749,7 +4749,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
self.networkResetTimer?.invalidate()
self.networkResetTimer = nil
}
SecureLogger.log("⏳ Mesh empty — reset network notification state", category: SecureLogger.session, level: .debug)
SecureLogger.log("⏳ Mesh empty — reset network notification state", category: .session, level: .debug)
}
// Register ephemeral sessions for all connected peers
@@ -4812,7 +4812,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
if !idsToRemove.isEmpty {
SecureLogger.log("🧹 Cleaned up \(idsToRemove.count) stale unread peer IDs",
category: SecureLogger.session, level: .debug)
category: .session, level: .debug)
}
}
@@ -4843,7 +4843,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
let removedCount = oldCount - sentReadReceipts.count
if removedCount > 0 {
SecureLogger.log("🧹 Cleaned up \(removedCount) old read receipts",
category: SecureLogger.session, level: .debug)
category: .session, level: .debug)
}
}
@@ -4891,7 +4891,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
nostrPublicKey = data.hexEncodedString()
}
} catch {
SecureLogger.log("Failed to decode Nostr npub: \(error)", category: SecureLogger.session, level: .error)
SecureLogger.log("Failed to decode Nostr npub: \(error)", category: .session, level: .error)
}
}
@@ -5032,7 +5032,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
NostrRelayManager.shared.sendEvent(event, to: targetRelays)
}
} catch {
SecureLogger.log("❌ Failed to send geohash raw message: \(error)", category: SecureLogger.session, level: .error)
SecureLogger.log("❌ Failed to send geohash raw message: \(error)", category: .session, level: .error)
}
}
return
@@ -5048,12 +5048,12 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
@MainActor
private func setupNostrMessageHandling() {
guard let currentIdentity = try? NostrIdentityBridge.getCurrentNostrIdentity() else {
SecureLogger.log("⚠️ No Nostr identity available for message handling", category: SecureLogger.session, level: .warning)
SecureLogger.log("⚠️ No Nostr identity available for message handling", category: .session, level: .warning)
return
}
SecureLogger.log("🔑 Setting up Nostr subscription for pubkey: \(currentIdentity.publicKeyHex.prefix(16))...",
category: SecureLogger.session, level: .debug)
category: .session, level: .debug)
// Subscribe to Nostr messages
let filter = NostrFilter.giftWrapsFor(
@@ -5093,19 +5093,19 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
// Expect embedded BitChat packet content
guard content.hasPrefix("bitchat1:") else {
SecureLogger.log("Ignoring non-embedded Nostr DM content", category: SecureLogger.session, level: .debug)
SecureLogger.log("Ignoring non-embedded Nostr DM content", category: .session, level: .debug)
return
}
guard let packetData = Self.base64URLDecode(String(content.dropFirst("bitchat1:".count))),
let packet = BitchatPacket.from(packetData) else {
SecureLogger.log("Failed to decode embedded BitChat packet from Nostr DM", category: SecureLogger.session, level: .error)
SecureLogger.log("Failed to decode embedded BitChat packet from Nostr DM", category: .session, level: .error)
return
}
// Only process typed noiseEncrypted envelope for private messages/receipts
guard packet.type == MessageType.noiseEncrypted.rawValue else {
SecureLogger.log("Unsupported embedded packet type: \(packet.type)", category: SecureLogger.session, level: .warning)
SecureLogger.log("Unsupported embedded packet type: \(packet.type)", category: .session, level: .warning)
return
}
@@ -5119,7 +5119,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
// Parse plaintext typed payload
guard let noisePayload = NoisePayload.decode(packet.payload) else {
SecureLogger.log("Failed to parse embedded NoisePayload", category: SecureLogger.session, level: .error)
SecureLogger.log("Failed to parse embedded NoisePayload", category: .session, level: .error)
return
}
@@ -5215,14 +5215,14 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
// Send delivery ack via Nostr embedded
if !wasReadBefore {
if let key = actualSenderNoiseKey {
SecureLogger.log("Sending DELIVERED ack for \(messageId.prefix(8))… via router", category: SecureLogger.session, level: .debug)
SecureLogger.log("Sending DELIVERED ack for \(messageId.prefix(8))… via router", category: .session, level: .debug)
messageRouter.sendDeliveryAck(messageId, to: key.hexEncodedString())
} else if let id = try? NostrIdentityBridge.getCurrentNostrIdentity() {
// Fallback: no Noise mapping yet send directly to sender's Nostr pubkey
let nt = NostrTransport()
nt.senderPeerID = meshService.myPeerID
nt.sendDeliveryAckGeohash(for: messageId, toRecipientHex: senderPubkey, from: id)
SecureLogger.log("Sent DELIVERED ack directly to Nostr pub=\(senderPubkey.prefix(8))… for mid=\(messageId.prefix(8))", category: SecureLogger.session, level: .debug)
SecureLogger.log("Sent DELIVERED ack directly to Nostr pub=\(senderPubkey.prefix(8))… for mid=\(messageId.prefix(8))", category: .session, level: .debug)
}
}
@@ -5237,7 +5237,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
if !sentReadReceipts.contains(messageId) {
if let key = actualSenderNoiseKey {
let receipt = ReadReceipt(originalMessageID: messageId, readerID: meshService.myPeerID, readerNickname: nickname)
SecureLogger.log("Viewing chat; sending READ ack for \(messageId.prefix(8))… via router", category: SecureLogger.session, level: .debug)
SecureLogger.log("Viewing chat; sending READ ack for \(messageId.prefix(8))… via router", category: .session, level: .debug)
messageRouter.sendReadReceipt(receipt, to: key.hexEncodedString())
sentReadReceipts.insert(messageId)
} else if let id = try? NostrIdentityBridge.getCurrentNostrIdentity() {
@@ -5245,7 +5245,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
nt.senderPeerID = meshService.myPeerID
nt.sendReadReceiptGeohash(messageId, toRecipientHex: senderPubkey, from: id)
sentReadReceipts.insert(messageId)
SecureLogger.log("Viewing chat; sent READ ack directly to Nostr pub=\(senderPubkey.prefix(8))… for mid=\(messageId.prefix(8))", category: SecureLogger.session, level: .debug)
SecureLogger.log("Viewing chat; sent READ ack directly to Nostr pub=\(senderPubkey.prefix(8))… for mid=\(messageId.prefix(8))", category: .session, level: .debug)
}
}
} else {
@@ -5290,7 +5290,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
}
} catch {
SecureLogger.log("Failed to decrypt Nostr message: \(error)", category: SecureLogger.session, level: .error)
SecureLogger.log("Failed to decrypt Nostr message: \(error)", category: .session, level: .error)
}
}
@@ -5311,7 +5311,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
// Parse ACK format: "ACK:TYPE:MESSAGE_ID"
let parts = content.split(separator: ":", maxSplits: 2)
guard parts.count >= 3 else {
SecureLogger.log("⚠️ Invalid ACK format: \(content)", category: SecureLogger.session, level: .warning)
SecureLogger.log("⚠️ Invalid ACK format: \(content)", category: .session, level: .warning)
return
}
@@ -5327,7 +5327,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
processedNostrAcks.insert(ackKey)
SecureLogger.log("📨 Received \(ackType) ACK for message \(messageId.prefix(16))... from \(senderPubkey.prefix(16))...",
category: SecureLogger.session, level: .debug)
category: .session, level: .debug)
// Verify the sender has a valid Noise key
guard findNoiseKey(for: senderPubkey) != nil else {
@@ -5346,12 +5346,12 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
case "READ":
privateChats[chatPeerID]?[index].deliveryStatus = .read(by: "recipient", at: Date())
default:
SecureLogger.log("⚠️ Unknown ACK type: \(ackType)", category: SecureLogger.session, level: .warning)
SecureLogger.log("⚠️ Unknown ACK type: \(ackType)", category: .session, level: .warning)
}
messageFound = true
SecureLogger.log("✅ Updated message \(messageId.prefix(16))... status to \(ackType) in chat \(chatPeerID.prefix(16))...",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
// Don't break - continue to update in all chats where this message exists
}
}
@@ -5360,7 +5360,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
objectWillChange.send()
} else {
SecureLogger.log("⚠️ Could not find message \(messageId) to update status from ACK",
category: SecureLogger.session, level: .warning)
category: .session, level: .warning)
}
}
@@ -5387,7 +5387,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
if parts.count > 1 {
nostrPubkey = String(parts[1])
SecureLogger.log("📝 Received Nostr npub in favorite notification: \(nostrPubkey ?? "none")",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
}
// Get the noise public key for this peer
@@ -5406,7 +5406,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
guard let finalNoiseKey = noiseKey else {
SecureLogger.log("⚠️ Cannot get Noise key for peer \(peerID)",
category: SecureLogger.session, level: .warning)
category: .session, level: .warning)
return
}
@@ -5421,7 +5421,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
// If they favorited us and provided their Nostr key, ensure it's stored
if isFavorite && nostrPubkey != nil {
SecureLogger.log("💾 Storing Nostr key association for \(senderNickname): \(nostrPubkey!.prefix(16))...",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
}
// Show system message
@@ -5533,7 +5533,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
}
SecureLogger.log("📬 Stored Nostr message from unknown sender \(finalSenderNickname) in temporary peer \(tempPeerID)",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
}
@MainActor
@@ -5546,7 +5546,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
// Try to convert hex to npub
guard let pubkeyData = Data(hexString: nostrPubkey) else {
SecureLogger.log("⚠️ Invalid hex public key format: \(nostrPubkey.prefix(16))...",
category: SecureLogger.session, level: .warning)
category: .session, level: .warning)
return nil
}
@@ -5554,7 +5554,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
npubToMatch = try Bech32.encode(hrp: "npub", data: pubkeyData)
} catch {
SecureLogger.log("⚠️ Failed to convert hex to npub: \(error)",
category: SecureLogger.session, level: .warning)
category: .session, level: .warning)
return nil
}
}
@@ -5565,21 +5565,21 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
// Compare npub format
if storedNostrKey == npubToMatch {
// SecureLogger.log(" Found Noise key for Nostr sender (npub match)",
// category: SecureLogger.session, level: .debug)
// category: .session, level: .debug)
return noiseKey
}
// Also try hex comparison if stored value is hex
if !storedNostrKey.hasPrefix("npub") && storedNostrKey == nostrPubkey {
SecureLogger.log("✅ Found Noise key for Nostr sender (hex match)",
category: SecureLogger.session, level: .debug)
category: .session, level: .debug)
return noiseKey
}
}
}
SecureLogger.log("⚠️ No matching Noise key found for Nostr pubkey: \(nostrPubkey.prefix(16))... (tried npub: \(npubToMatch.prefix(16))...)",
category: SecureLogger.session, level: .debug)
category: .session, level: .debug)
return nil
}
@@ -5607,13 +5607,13 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
// Try mesh first for connected peers
if meshService.isPeerConnected(peerID) {
messageRouter.sendFavoriteNotification(to: peerID, isFavorite: isFavorite)
SecureLogger.log("📤 Sent favorite notification via BLE to \(peerID)", category: SecureLogger.session, level: .debug)
SecureLogger.log("📤 Sent favorite notification via BLE to \(peerID)", category: .session, level: .debug)
} else if let key = noiseKey {
// Send via Nostr for offline peers (using router)
let recipientPeerID = key.hexEncodedString()
messageRouter.sendFavoriteNotification(to: recipientPeerID, isFavorite: isFavorite)
} else {
SecureLogger.log("⚠️ Cannot send favorite notification - peer not connected and no Nostr pubkey", category: SecureLogger.session, level: .warning)
SecureLogger.log("⚠️ Cannot send favorite notification - peer not connected and no Nostr pubkey", category: .session, level: .warning)
}
}
@@ -5704,11 +5704,11 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
} else {
// Keep old messages in original location but don't show in UI
SecureLogger.log("📦 Partially migrating \(recentMessages.count) of \(messages.count) messages from \(oldPeerID)",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
}
SecureLogger.log("📦 Migrating \(recentMessages.count) recent messages from old peer ID \(oldPeerID) to \(peerID) (fingerprint match)",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
} else if currentFingerprint == nil || oldFingerprint == nil {
// Check if this chat contains messages with this sender by nickname
let isRelevantChat = recentMessages.contains { msg in
@@ -5725,7 +5725,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
}
SecureLogger.log("📦 Migrating \(recentMessages.count) recent messages from old peer ID \(oldPeerID) to \(peerID) (nickname match)",
category: SecureLogger.session, level: .warning)
category: .session, level: .warning)
}
}
}
@@ -5765,7 +5765,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
if needsSelectedUpdate {
selectedPrivateChatPeer = peerID
SecureLogger.log("📱 Updated selectedPrivateChatPeer from old ID to \(peerID) during migration",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
}
}
}
@@ -5774,11 +5774,11 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
/// Handle incoming private message
@MainActor
private func handlePrivateMessage(_ message: BitchatMessage) {
SecureLogger.log("📥 handlePrivateMessage called for message from \(message.sender)", category: SecureLogger.session, level: .debug)
SecureLogger.log("📥 handlePrivateMessage called for message from \(message.sender)", category: .session, level: .debug)
let senderPeerID = message.senderPeerID ?? getPeerIDForNickname(message.sender)
guard let peerID = senderPeerID else {
SecureLogger.log("⚠️ Could not get peer ID for sender \(message.sender)", category: SecureLogger.session, level: .warning)
SecureLogger.log("⚠️ Could not get peer ID for sender \(message.sender)", category: .session, level: .warning)
return
}
@@ -5819,7 +5819,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
privateChats.removeValue(forKey: stableKeyHex)
SecureLogger.log("📥 Consolidated \(nostrMessages.count) Nostr messages from stable key to ephemeral peer \(peerID)",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
}
}
}
@@ -6087,7 +6087,7 @@ private func checkForMentions(_ message: BitchatMessage) {
if isMentioned && message.sender != nickname {
SecureLogger.log("🔔 Mention from \(message.sender)",
category: SecureLogger.session, level: .info)
category: .session, level: .info)
NotificationService.shared.sendMentionNotification(from: message.sender, message: message.content)
}
}