* Expand coverage for relay, identity, and location flows
* Fix macOS SwiftPM CI failures
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* feat: Implement Request Sync Manager (V2 Sync)
- Add RequestSyncManager to track and attribute sync requests
- Update BitchatPacket and BinaryProtocol to support IS_RSR flag (0x10)
- Update RequestSyncPacket with new TLV fields (sinceTimestamp, fragmentIdFilter)
- Update GossipSyncManager to use unicast sync requests and mark responses as RSR
- Update BLEService to enforce timestamp validation for normal packets and exempt valid RSRs
- Add documentation for the new sync manager mechanism
* fix: Resolve compilation errors in V2 Sync implementation
- Remove duplicate restartGossipManager in BLEService
- Add missing TransportConfig constants for sync
- Add 'sync' log category to BitLogger
- Add missing BitLogger import in GossipSyncManager
* fix: Update tests for V2 Sync changes
- Add requestSyncManager parameter to GossipSyncManager init in tests
- Implement getConnectedPeers stub in RecordingDelegate
- Remove unused variable warning in SubscriptionRateLimitTests
---------
Co-authored-by: a1denvalu3 <>
Co-authored-by: jack <212554440+jackjackbits@users.noreply.github.com>
* Improve BLE mesh reliability for large transfers
Major reliability improvements for fragment-based transfers (photos, files):
**Notification Queue Fixes**
- Fix silent packet loss when notification queue is full - now queues for retry
- Fix retry queue bug where remaining items were lost when one retry failed
- Add periodic drain mechanism as backup (every 5 seconds)
**Write Queue Fixes**
- Fix drainPendingWrites to use atomic take-send-requeue pattern
- Add logging when peripheral is ready for more writes
- Add periodic drain for pending writes as backup
**Fragment Pacing**
- Increase fragment spacing from 4-5ms to 25-30ms to prevent buffer overflow
- Conservative pacing prevents packet loss on congested BLE connections
**Thread Safety**
- Fix race conditions in stopServices() and emergencyDisconnectAll()
- Synchronize access to peripherals/centrals dictionaries during cleanup
- Clear pending message queues in emergencyDisconnectAll()
**Error Recovery**
- Add handlers for all BLE state transitions (poweredOff, unauthorized, etc.)
- Clear Noise session and re-initiate handshake on decryption failure
- Queue ACKs/receipts for delivery after handshake instead of dropping
- Re-queue failed pending messages for retry
**Other Improvements**
- Add route freshness validation in MeshTopologyTracker (60s threshold)
- Add TTL (24h) and size limits (100 per peer) for MessageRouter outbox
- Fix connection timeout to check peripheral.state before canceling
- Add NoiseEncryptionService.clearSession(for:) method
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Fix race condition and increase test timeouts
- Fix race in sendNoisePayload: use sync barrier instead of async
to ensure payload is queued before initiating handshake
(addresses Codex review feedback)
- Increase BLEServiceTests sleep from 0.5s to 1.0s for CI reliability
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Add comprehensive test coverage for ChatViewModel and BLEService
This commit adds 14 new tests to improve the safety net for future
refactoring of ChatViewModel and BLEService:
New test files:
- ChatViewModelTorTests: Tor lifecycle notification handlers (8 tests)
- ChatViewModelDeliveryStatusTests: Delivery status state machine (6 tests)
- ChatViewModelRefactoringTests: Command routing and message handling (4 tests)
- BLEServiceCoreTests: Packet deduplication and stale broadcast filtering (2 tests)
- PublicMessagePipelineTests: Message ordering and deduplication (4 tests)
- MessageRouterTests: Transport selection and outbox behavior (4 tests)
- PrivateChatManagerTests: Chat selection and read receipts (2 tests)
- UnifiedPeerServiceTests: Fingerprint resolution and blocking (2 tests)
- RelayControllerTests: TTL, handshake, and fragment relay logic (4 tests)
Modified files:
- MockTransport: Added peer snapshot publishing on connect/disconnect
- TestHelpers: Added waitUntil polling helper for async tests
- MockIdentityManager: Extended for new test scenarios
Total: 454 tests across 64 suites (was 440)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Fix flaky test by using waitUntil instead of fixed sleep
Replace fixed 200ms sleep with waitUntil helper for more reliable
async assertion in routing tests. This prevents timing issues on CI.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
When selectedPrivateChatPeer was migrated to a 64-hex stable Noise key
after session establishment, file transfers would silently fail because:
1. Sender used raw 64-hex key, truncated to first 8 bytes by BinaryProtocol
2. Receiver's myPeerID is SHA256-fingerprint-derived (different value)
3. Recipient check failed, causing silent packet drop
The fix normalizes peerID to short form (SHA256-derived 16-hex) in
sendFilePrivate before constructing recipientData, ensuring the wire
format matches what receivers expect.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Block notifications from bypassing the user blocking feature on iOS.
Vulnerabilities fixed:
1. Nostr public messages: checkForMentions() was called regardless of
blocking status, allowing blocked users to trigger mention notifications
2. Noise-encrypted DMs: didReceiveNoisePayload() didn't check blocking
before calling handlePrivateMessage(), allowing DM notifications
Changes:
- ChatViewModel+Nostr.swift: Add blocking check before checkForMentions()
and sendHapticFeedback() in subscribeNostrEvent
- ChatViewModel.swift: Add isPeerBlocked() check in didReceiveNoisePayload
before processing private messages
- Add NotificationBlockingTests.swift with 5 tests for blocking behavior
Security: Blocked users can no longer trigger notifications through any
message path (Nostr public, Nostr DM, or BLE Noise DM).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add proper error classification to distinguish expected states (item not
found) from critical failures (access denied, storage full) and
recoverable errors (device locked, auth failed).
Changes:
- Add KeychainReadResult and KeychainSaveResult enums with error types
- Add getIdentityKeyWithResult/saveIdentityKeyWithResult protocol methods
- Implement retry logic with exponential backoff for transient errors
- Add consistent SecureLogger logging for all keychain operations
- Update NoiseEncryptionService identity loading to handle errors gracefully
- Update MockKeychain and TrackingMockKeychain with error simulation
- Add comprehensive KeychainErrorHandlingTests (18 new tests)
Security: Applications can now properly detect and respond to critical
keychain failures, improving resilience during device lock states and
providing actionable diagnostics for access issues.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
BCH-01-011: Reduces replay attack window from ±1 hour to ±5 minutes.
The previous 1-hour window allowed extended replay attacks. A 5-minute
window is industry standard for replay protection while accommodating
reasonable clock drift.
- Updated InputValidator.validateTimestamp to use 300-second window
- Updated tests to verify new boundary conditions
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds rate-limiting to prevent device enumeration attacks via rapid
subscription/disconnect cycles. Without this fix, an attacker could
enumerate ~120 bitchat devices per minute by connecting, subscribing,
capturing the announce packet, then disconnecting and moving to the next.
Key changes:
- Add per-central rate-limit tracking with exponential backoff
- Minimum 2-second interval between announces per central
- Exponential backoff (2x) up to 30 seconds for rapid reconnects
- After 5 rapid attempts, suppress announces entirely (likely attack)
- Clean up stale rate-limit entries after 60-second window
- Clear rate-limit state during panic mode
Configuration:
- bleSubscriptionRateLimitMinSeconds: 2.0
- bleSubscriptionRateLimitBackoffFactor: 2.0
- bleSubscriptionRateLimitMaxBackoffSeconds: 30.0
- bleSubscriptionRateLimitWindowSeconds: 60.0
- bleSubscriptionRateLimitMaxAttempts: 5
Security audit reference: Cure53 BCH-01-004 (Medium severity)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add recheck of message count after acquiring lock and before storing
continuation to prevent race where message arrives between initial
count check and continuation install.
Addresses Codex review feedback on PR #931.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace timing-based sleep() synchronization with continuation-based waiting
in FragmentationTests to fix intermittent failures.
Changes:
- Add thread-safe CaptureDelegate with NSLock for array access
- Add waitForPublicMessages/waitForReceivedMessages using CheckedContinuation
- Update reassemblyFromFragmentsDeliversPublicMessage to use proper waiting
- Update duplicateFragmentDoesNotBreakReassembly to use proper waiting
- Remove fire-and-forget Task blocks that caused race conditions
Root cause: Tests used fire-and-forget Tasks with sleep(0.5) but delegate
callbacks go through notifyUI() which spawns another MainActor Task.
The sleep didn't guarantee callback completion.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added @MainActor annotation to both LRUDeduplicationCache and
MessageDeduplicationService classes. This provides compile-time
enforcement of thread safety since all callers (ChatViewModel,
NostrRelayManager) are already on MainActor.
Benefits:
- Compile-time enforcement prevents future misuse
- Simpler than internal locking mechanisms
- Consistent with existing patterns in codebase
Also adds:
- @MainActor annotation to existing test suites
- 5 new concurrency tests verifying thread safety behavior
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Synchronized access to readQueue and isSendingReadAcks using the
existing concurrent DispatchQueue with barrier flags:
- sendReadReceipt(): wrap enqueue in barrier async
- processReadQueueIfNeeded(): extract item within barrier context
- scheduleNextReadAck(): wrap callback in barrier async
This fixes race conditions where concurrent calls could corrupt the
read queue or cause check-then-act bugs on isSendingReadAcks.
Also adds thread safety tests:
- concurrentReadReceiptEnqueue: 100 concurrent enqueue operations
- readQueueProcessingUnderLoad: concurrent enqueue during processing
- isPeerReachableThreadSafety: concurrent read access test
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added secureClear() calls for all 6 DH operations in NoiseProtocol.swift
to properly clear sensitive shared secrets from memory after use:
- writeMessage(): .es initiator/responder, .se initiator/responder
- performDHOperation(): .ee and .ss operations
This fixes a forward secrecy vulnerability where shared secrets could
persist in memory after handshake completion.
Also adds:
- TrackingMockKeychain to count secureClear calls in tests
- 3 new tests verifying secureClear is called during handshake
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Merge KeychainHelper functionality into KeychainManager to provide
a single, unified API for all keychain operations.
- Remove KeychainHelper.swift and KeychainHelperProtocol
- Add generic save/load/delete methods to KeychainManagerProtocol
- Update NostrIdentityBridge to use KeychainManagerProtocol
- Update FavoritesPersistenceService to use KeychainManagerProtocol
- Update PreviewKeychainManager with new methods
- Update MockKeychain and add MockKeychainHelper typealias for backwards compatibility
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Refactor message formatting logic into a dedicated, testable class:
- Create MessageFormattingEngine with Patterns enum (precompiled regexes)
- Create MessageFormattingContext protocol for dependency injection
- Extract extractMentions(), containsCashuToken(), and pattern matchers
- Add 28 comprehensive tests for formatting utilities
- Update ChatViewModel to conform to MessageFormattingContext
This prepares for further message formatting extraction and makes
regex patterns and utility functions testable in isolation.
Refactor participant tracking logic into a dedicated, testable class:
- Create GeohashParticipantTracker with GeohashParticipantContext protocol
- Move GeoPerson struct to new file
- Extract participant recording, refresh, and count logic
- Add 18 comprehensive tests for the tracker
- Update ChatViewModel to use tracker via dependency injection
- Subscribe to tracker's objectWillChange for SwiftUI observation
This reduces coupling in ChatViewModel and makes participant tracking
testable in isolation.
The original tests using in-place Data modification with `data[0] ^= 0xFF`
caused signal 5 crashes during parallel test execution. Fixed by:
- Using `import struct Foundation.Data` for efficiency
- Converting Data to byte array before modification to avoid the crash
- Simplified error-throwing tests to use boolean flags instead of
complex error type matching
* Simplify validation, compression heuristics, and notification scheduling
* Consolidate notification logic and add InputValidator monitoring
Follow-up improvements to address PR feedback:
1. Consolidate notification functions
- Add interruptionLevel parameter to sendLocalNotification
- Refactor sendNetworkAvailableNotification to use consolidated function
- Removes 12 lines of duplicate code
2. Add monitoring to InputValidator
- Log control character rejections for production monitoring
- Privacy-preserving: logs length + count, not actual content
- Uses .security category for proper log routing
3. Add comprehensive InputValidator tests
- 28 test cases covering validation, control characters, unicode, edge cases
- Ensures behavioral changes are well-tested and documented
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* PeerID 28/n: `ChatViewModel.getShortIDForNoiseKey`
* PeerID 29/n: `BLEService` + remove dupe funcs from #823
* `handleFileTransfer` to use PeerID
* `sendMessage` and `sendPrivateMessage`
* PeerID 30/n: Update some leftovers
* `lowercased()` inside PeerID for normalization
* PeerID 31/n: Remove String interop to be explicit
* MockBLEService: Remove direct target delivery
This causes a delivery even if the sender and receiver are not connected
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>