Commit Graph
64 Commits
Author SHA1 Message Date
jack 25efa62587 Merge remote-tracking branch 'origin/feat/wifi-bulk-transport' into feat/integration-all
# Conflicts:
#	bitchat/Protocols/BitchatProtocol.swift
#	bitchat/Protocols/PeerCapabilities+Local.swift
#	bitchat/ViewModels/ChatTransportEventCoordinator.swift
#	bitchat/ViewModels/NostrInboundPipeline.swift
2026-07-06 22:18:59 +02:00
jack 20cdd6653a Merge remote-tracking branch 'origin/feat/private-groups' into feat/integration-all
# Conflicts:
#	bitchat/Protocols/BitchatProtocol.swift
#	bitchat/Protocols/PeerCapabilities+Local.swift
#	bitchat/Services/BLE/BLEOutboundPacketPolicy.swift
#	bitchat/Services/BLE/BLEService.swift
#	bitchat/Services/Transport.swift
#	bitchat/Sync/GossipSyncManager.swift
#	bitchat/Sync/SyncTypeFlags.swift
#	bitchat/ViewModels/ChatTransportEventCoordinator.swift
#	bitchat/ViewModels/ChatViewModel.swift
#	bitchat/ViewModels/NostrInboundPipeline.swift
#	bitchatTests/ChatTransportEventCoordinatorContextTests.swift
#	bitchatTests/GossipSyncManagerTests.swift
#	localPackages/BitFoundation/Sources/BitFoundation/MessageType.swift
2026-07-06 22:13:31 +02:00
jackandClaude Fable 5 e4b3cff5fa Wi-Fi bulk transport: AWDL data plane for large media with BLE fallback
BLE stays the control plane: a sender with a queued file > 64 KiB to a
directly connected peer advertising the wifiBulk capability sends a
bulkTransferOffer (0x04) inside the established Noise session — transferID,
file size, payload SHA-256, a fresh 32-byte token, and a random per-transfer
Bonjour instance name. The receiver answers bulkTransferResponse (0x05) with
its own token half, then both sides meet on a per-transfer
_bitchat-bulk._tcp channel over peer-to-peer Wi-Fi (AWDL).

The TCP stream is secured independently of TLS: both tokens traveled inside
Noise, so only the two peers can derive the ChaChaPoly channel key
(HKDF-SHA256, domain "bitchat-bulk-v1", transferID as salt). Frames are
length-prefixed sealed boxes with structured direction+counter nonces; the
first frame must prove knowledge of the key or the client is disconnected,
and the final hash is verified against the offer before delivery.

Decline, timeout, or any mid-transfer error falls back to BLE fragmentation
exactly once, driving the same TransferProgressManager stream so the UI is
unchanged. Wi-Fi-negotiated transfers may carry up to 8 MiB (new
FileTransferLimits.maxWifiBulkPayloadBytes, enforced by the receiver from
the accepted offer); the BLE path keeps its existing caps.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 20:35:40 +02:00
jackandClaude Fable 5 7ad19ab4c3 Private groups: creator-managed encrypted group chat over the mesh
Small encrypted crews (hard cap 16) between public broadcast and 1:1 DMs:

Protocol
- MessageType.groupMessage = 0x25: broadcast packets with a cleartext
  16-byte group ID + epoch, ChaCha20-Poly1305 ciphertext (epoch bound as
  AEAD AAD), inner Ed25519 sender signature over
  "bitchat-group-msg-v1"|groupID|messageID|timestamp|content
- NoisePayloadType.groupInvite = 0x06 / .groupKeyUpdate = 0x07:
  creator-signed group state (key, epoch, roster) 1:1 over Noise; signature
  over "bitchat-group-v1"|groupID|epoch|key-hash|roster-hash and the Noise
  session peer must BE the creator
- SyncTypeFlags bit 10 (groupMessage): variable-length LE bitfield widens
  1 -> 2 bytes inside the length-prefixed REQUEST_SYNC TLV; old clients
  ignore unknown bits and answer with types they know
- PeerCapabilities.localSupported now advertises .groups

Storage
- GroupStore: symmetric keys in the keychain, roster/name/epoch as
  protected JSON in Application Support; wiped in panicClearAllData()

Behavior
- Non-members relay 0x25 like any broadcast but cannot read it; group
  messages join gossip-sync backfill with the public-message window
- Receivers drop wrong-epoch envelopes, bad sender signatures, and
  senders missing from the creator-signed roster
- Fire-and-flood delivery (no per-member acks in v1)

UI
- Groups open as chat windows through the private-chat sheet (virtual
  "group_" peer IDs); groups section in the people sheet; /group
  create/invite/remove/leave/list commands; invitees get a system message
  + notification and the group appears in their people sheet

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 20:22:38 +02:00
jackandClaude Fable 5 26b247c329 Transitive verification: vouch for verified peers over Noise
When a Noise session establishes with a peer I verified and that peer
advertises the .vouch capability, send signed attestations (up to 16,
most recently verified first, at most once per peer per 24h) for the
OTHER fingerprints I verified. Receivers accept vouches only from
senders they verified themselves, verify the Ed25519 signature against
the sender's announce-bound signing key, and surface the result as a
new derived trust tier: vouched (unfilled seal) between casual and
trusted.

Protocol:
- NoisePayloadType.vouch = 0x12 carries a batch of TLV attestations:
  voucheeFingerprint (32B), voucheeSigningKey (32B), timestamp
  (uint64 ms BE), Ed25519 signature over
  "bitchat-vouch-v1" | fingerprint | signingKey | timestamp.
  The voucher is implicit in the authenticated session.
- PeerCapabilities.localSupported now advertises .vouch.

Storage (SecureIdentityStateManager / IdentityCache):
- vouches keyed by vouchee, capped at 8 vouchers each; validity is
  recomputed on read (voucher still verified-by-me, < 30 days old), so
  unverifying a voucher retires their vouches without cascade deletes.
- New IdentityCache fields are Optional so pre-existing encrypted
  caches decode cleanly; TrustLevel.vouched is inserted mid-ladder but
  raw values are strings, so persisted values are unaffected (and
  vouched itself is never persisted).
- Panic wipe clears vouch state with the rest of the identity cache.

UI: unfilled checkmark.seal badge in the mesh peer list (filled seal
stays exclusive to verified) and a "vouched for by N people you
verified" section with voucher names in FingerprintView; VoiceOver
labels and xcstrings entries included.

Tests: attestation encode/decode + signature (forged/tampered/expired),
accept-policy gates, batch cap, trust-level derivation incl. voucher
invalidation, persistence compat, and coordinator exchange/accept
policies. Full macOS suite: 1088 tests passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 20:13:48 +02:00
IslamandGitHub c60eff2c11 Move additional files/tests to BitFoundation (#1102) 2026-04-15 12:26:48 -05:00
IslamandGitHub 4cfcefcda6 BitFoundation module to centralize shared components (#1089)
* Run local packages’ tests as well on CI

* BitFoundation module to centralize shared components
2026-04-14 14:10:03 -05:00
83779240ae Prevent mesh self-sync duplicates (#856)
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-10-23 10:41:28 +02:00
40e54a5120 Add voice notes and images over BLE mesh (audio + image only) (#823)
* Add BLE file transfer support and media UX

* Gracefully disable mac attachment pickers in sandbox

* Tighten spacing above media message bubbles

* Reduce vertical padding between chat rows

* Restore iOS file importer for attachments

* Copy imported files before sending to preserve access

* Allow file transfers from connected but unverified peers

* Raise BLE notification buffer cap for large file transfers

* Revert "Raise BLE notification buffer cap for large file transfers"

This reverts commit b624523af843475db84e4a846db8dcbe824ae408.

* Add guard to drop oversized BLE notification assemblies

* Let BLE assembler accept large frames up to hard cap

* Add detailed logging for BLE fragment assembly

* Log incomplete BLE frames for debugging

* Stop dropping partial BLE frames while assembling notifications

* Fix compressed BLE file transfers

* Enable mac attachment importers

* Allow mac microphone access

* Permit mac media library access

* Describe microphone usage

* Harden attachment transfer bookkeeping

* Display recording milliseconds

* Restore mac photo picker access

* Use Photos picker on mac

* Allow long-press reblur on images

* Reblur images via swipe

* Lowercase image preview buttons

* Keep processed images for outgoing messages

* Use save panel for mac image export

* Fix image attachment detection

* Allow user-selected write access

* Align mac image JPEG encoding

* Revert unsupported JPEG option

* Strip metadata in mac image encoding

* Normalize mac JPEG color space

* Target image byte size across platforms

* Fix CFMutableData handling

* Preserve packet version when signing

* Use unique transfer identifiers

* Stub file transfer methods in mock

* Stub file transfer methods in mock

* Hide absolute paths in media messages

* Resolve image/voice path handling

* Fix cleanupLocalFile lookup

* Restore BLE broadcasts when notify buffer is saturated

* Guard peer map reads on BLE message path

* Drop attachment ceilings to 1 MiB and bump release version

* Reset BLE assembler on stalled fragment trains

* Fix binary protocol test fixtures

* Fix critical issues from PR #681 review

Critical fixes:
- BinaryProtocol: Return nil for unknown versions (prevents buffer underflows)
- Add BinaryProtocol.Offsets struct to centralize magic numbers
- Replace magic offset calculations with named constants

Security/Privacy:
- FileAttachmentView: Use url.lastPathComponent instead of url.path
  (prevents exposing full system paths)

Documentation:
- Fix compression algorithm documentation (zlib, not LZ4)

All tests passing.

* Fix UI freeze when receiving voice notes

Problem: AVAudioPlayer initialization in VoiceNotePlaybackController.init()
was running synchronously on main thread during view creation, blocking
UI for 50-200ms per voice note.

Solution:
- Remove eager preparePlayer() call from init
- Load duration asynchronously on background queue
- Player is only prepared when playback is actually requested via ensurePlayerReady()

This prevents UI freezes when voice notes appear in the chat.

* Fix memory leaks and post-playback freeze

Fixes:
1. Post-playback freeze: audioPlayerDidFinishPlaying now dispatches to main
   thread before updating @Published properties (Swift concurrency violation)

2. Unbounded waveform cache: Implement LRU eviction with 20-entry limit
   - Track last access time for each cached waveform
   - Evict oldest entry when cache is full
   - Prevents unlimited memory growth as voice notes accumulate

3. Audio buffer memory leaks: Wrap computeWaveform in autoreleasepool
   - AVAudioPCMBuffer allocations are autoreleased
   - Pool ensures buffers are freed promptly

4. Image processing memory: Add autoreleasepool around compression loops
   - Each jpegData() call creates temporary objects
   - Inner pool per iteration prevents memory spikes during quality search

Memory should now remain stable during extended use.

* Eliminate disk I/O from SwiftUI view rendering path

Critical performance fix for UI freezes when receiving media:

Problem: mediaAttachment(for:) was called during every SwiftUI render,
performing synchronous disk I/O on main thread:
- FileManager.fileExists() called 2-6x per message (checking subdirs)
- applicationFilesDirectory() creating directories on every call
- With multiple media messages, this meant 20-100+ disk ops per render

Solution:
1. Remove fileExists checks - construct URLs directly
   - Files are validated during playback/display (fail gracefully if missing)
   - Sender determines subdirectory (outgoing vs incoming)

2. Cache applicationFilesDirectory() result
   - Static cache prevents repeated FileManager.url() calls
   - Directory created only once

3. Remove redundant playback.replaceURL() in VoiceNoteView.onAppear
   - Controller already initialized with correct URL

This eliminates ALL disk I/O from the view rendering hot path.

* Cache Nostr identity derivation to prevent crypto during view rendering

Critical performance fix:

Problem: formatMessageHeader() called deriveIdentity(forGeohash:) during
every SwiftUI render for every media message. Each call performed:
- Keychain I/O (getOrCreateDeviceSeed)
- HMAC-SHA256 computation
- Up to 10 secp256k1 key validations (elliptic curve crypto)

With multiple media messages, this resulted in 100s of milliseconds of
blocking crypto on main thread per render cycle.

Solution: Add thread-safe cache for derived identities
- Check cache before expensive crypto operations
- NSLock protects concurrent access
- Identity is deterministic per geohash, so caching is safe

This eliminates crypto from the hot rendering path.

* Cache geohash identity in ChatViewModel to prevent crypto during rendering

Additional optimization for location channels (voice notes are mesh-only,
but this helps with text message rendering in geohash channels):

- Add cachedGeohashIdentity to avoid deriveIdentity calls during rendering
- Check cache before falling back to crypto derivation
- Reduces main thread crypto work in location channels

* Make voice note loading completely lazy with deferred initialization

Aggressive performance optimization to prevent UI freezes:

Problem: Even with async loading, creating 10+ VoiceNotePlaybackController
instances simultaneously (when scrolling past multiple voice notes) spawned
20+ concurrent background tasks, potentially starving main thread.

Solution - Ultra-lazy loading:
1. VoiceNotePlaybackController.init() now does ZERO work
   - No duration loading
   - No player creation
   - Instant initialization

2. Duration loaded on-demand via public loadDuration() method
   - Called from VoiceNoteView.onAppear after 150ms delay
   - Reduced priority: .utility instead of .userInitiated
   - Guard prevents duplicate loading

3. Waveform loading also deferred 150ms
   - Gives UI time to settle after message appears
   - Prevents task storms when multiple voice notes appear

This spreads the work over time instead of all at once.

* Ensure /clear and panic triple-tap delete media files

Fix: /clear command and panicClearAllData() now properly delete media files

1. /clear (triple-tap on chat):
   - Deletes outgoing media (voice notes, images, files)
   - Conservative: only our sent media, preserves received media
   - Runs in background to avoid UI freeze

2. panicClearAllData() (triple-tap on bitchat/ header):
   - Deletes ALL media files (incoming + outgoing)
   - Removes entire files directory and recreates structure
   - Ensures complete data wipe for emergency scenarios

Both operations run async on .utility queue to prevent blocking UI.

* Fix infinite render loop and apply all security fixes

CRITICAL BUG FIX - Infinite Render Loop:

Root Cause: Duplicate view identity in ContentView.swift:368
  ForEach(messageItems) { item in  // Already uses item.id via Identifiable
      messageRow(...)
          .id(item.id)  //  REDUNDANT modifier caused identity re-evaluation loop
  }

When @Published properties updated, SwiftUI re-evaluated .id() → appeared as
'new' identity → triggered re-render → infinite loop. Caused UI freezes,
keyboard failures, and 100% CPU usage.

Fix: Remove redundant .id() modifier - ForEach already has stable identity.

PERFORMANCE FIXES:

1. Waveform Cache Deadlock (Waveform.swift)
   - Removed nested queue.async(barrier) on cache hits
   - Was causing task saturation and potential deadlocks

2. Async Send Pattern (ContentView.swift)
   - Clear input immediately, defer actual send to next runloop
   - Prevents blocking current event handler

3. Proper Swift Concurrency (VoiceNoteView.swift)
   - Switch from .onAppear + DispatchQueue to .task
   - Cleaner async/await pattern for loading

4. Remove Redundant objectWillChange (ChatViewModel.swift)
   - @Published already triggers updates automatically
   - Explicit send() was causing double update cycles

SECURITY FIXES (C1-C5, H1-H2):

C1. Path Traversal Protection (BLEService.swift)
    - Unicode normalization, null byte removal
    - Replace ALL path separators, reject dotfiles
    - Validate paths don't escape directory

C2. Integer Overflow (BitchatFilePacket.swift)
    - Use UInt64 for TLV parsing, safe Int conversion

C3. MIME Validation (BLEService.swift)
    - Whitelist: JPEG, PNG, GIF, WebP, M4A, MP3, WAV, OGG, PDF
    - Magic byte validation for all types
    - Lenient on M4A (platform variations)

C4. Compression Bomb (BinaryProtocol.swift)
    - Ratio validation <= 50,000:1
    - Defense-in-depth with 1MB size cap

C5. TOCTOU Race (ChatViewModel.swift)
    - Direct removeItem without fileExists check

H1. File Size Validation (ChatViewModel, ImageUtils)
    - Check attributes BEFORE Data(contentsOf:)
    - Prevents memory exhaustion

H2. Metadata Stripping (ImageUtils.swift)
    - Remove ALL metadata keys from JPEG encoding
    - Only compression quality set
    - Protects GPS/EXIF/device info privacy

RESULT:
 No render loops
 Works with Xcode debugger
 Voice notes display properly
 All security vulnerabilities fixed
 164 tests passing

Production ready.

* Complete all translations to 100% and fix auto-extraction

- Mark non-localizable strings with Text(verbatim:) to prevent extraction
- Update UI strings to lowercase per style guide (open, save, close, recording)
- Add complete translations for all 29 languages (194/194 strings at 100%)
- Remove empty/duplicate entries (@, bitchat/, Open, Recording %@)
- Add proper localization comments for all user-facing strings

* macOS: Focus message input on launch instead of nickname field

* Remove debug print statements from sendMessage

* Optimize voice note codec to 16 kHz / 20 kbps for smaller file sizes

- Reduce sample rate from 44.1 kHz to 16 kHz (telephony standard)
- Lower bitrate from 32 kbps to 20 kbps
- Results in ~37% file size reduction (~150 KB/min vs 240 KB/min)
- Increases max voice note length from 4.4 to 7 minutes over 1 MiB BLE limit
- Maintains excellent voice quality using native AAC-LC codec

* Fix critical security issues in fragment reassembly and file cleanup

Fragment Reassembly Race Condition (CRITICAL):
- Wrap all incomingFragments/fragmentMetadata access in collectionsQueue.sync
- Prevents concurrent modification crashes from multi-threaded access
- Minimizes lock contention by doing heavy work (reassembly/decode) outside locks
- Add upper bound check: reject fragments with total > 10,000 (DoS prevention)
- Add cumulative size validation before storing fragments (memory DoS prevention)

File Cleanup Path Traversal (CRITICAL):
- Use NSString.lastPathComponent to extract filename safely
- Prevents directory traversal attacks via malicious filenames
- Add path prefix validation before file deletion
- Now checks both incoming and outgoing directories (fixes disk leak)

Additional Protections:
- Fragment assemblies now limited by both count (128) and cumulative bytes (1MB)
- Explicit checks for "." and ".." filenames in cleanup
- Defense-in-depth: multiple validation layers

* Fix post-rebase compilation errors

- Remove duplicate NostrIdentityBridge and Bech32 from NostrIdentity.swift (now in separate files)
- Add caching to NostrIdentityBridge.deriveIdentity() for performance
- Remove duplicate NotificationStreamAssembler from BLEService.swift
- Remove duplicate function declarations in BLEService.swift
- Remove duplicate DeliveryStatusView and PaymentChipView from ContentView.swift
- Fix PeerID type conversions throughout (use .id for String, PeerID(str:) for wrapping)
- Update ContentView body to use main's simple VStack structure
- Fix NostrIdentityBridge instance method calls
- Remove privateChatView (replaced with sheet-based UI in main)

Build and tests passing (137/139 tests pass).

* Fix remaining compilation issues after rebase

- Fix PhotosUI import order (must be after platform imports)
- Fix Data.WritingOptions.atomic reference
- Add identity derivation caching to NostrIdentityBridge
- Fix all remaining PeerID type conversions in ChatViewModel
- Fix ContentView body structure to use main's VStack layout
- Fix PaymentChipView API usage (now uses PaymentType enum)

Build and tests now passing.

* Add proper availability checks for PhotosPickerItem

PhotosPickerItem requires iOS 16+ / macOS 13+ but canImport(PhotosUI)
succeeds on older macOS versions. Add compiler version check to ensure
PhotosPicker code only compiles when actually available.

This fixes CI build failures on older macOS environments.

* Limit PhotosPicker to iOS only to fix CI

PhotosPickerItem has SDK availability issues on macOS in CI.
Change PhotosPicker from canImport(PhotosUI) to os(iOS) only.

macOS users can still import images via file importer (.fileImporter).
This is actually cleaner as macOS file picker is more familiar to users.

Fixes CI build failures.

* Convert new tests to Swift Testing

* Fix compilation issue

* Add the missing `fileTransfer` case

* Explicitly list all Enum cases to get compile-time errors

* Revive lost `NotificationStreamAssembler` changes

* Allow file fragments to account for protocol overhead

* Simplify PR: Focus on audio+image, fix EXIF stripping, remove file transfers

- Fix critical EXIF privacy issue in iOS image processing
  - Both iOS and macOS now use CGImageDestination for metadata stripping
  - Shared encodeJPEG function ensures no GPS, camera, or metadata leaks

- Remove file transfer functionality to simplify PR scope
  - Deleted FileAttachmentView
  - Removed sendFileAttachment from ChatViewModel
  - Removed file picker UI from ContentView
  - Simplified attachment dialog to image only (iOS) or voice only

- Keep focused media features:
  - Voice recording and playback
  - Image sending with progressive reveal
  - Binary protocol for media transfer

* Improve camera UX: Direct camera access with camera icon

- Change paperclip icon to camera icon for clearer affordance
- Open camera directly on tap (no confirmation dialog)
- Add CameraPickerView wrapper for UIImagePickerController
- Remove PhotosPicker in favor of direct camera access
- Images still processed through ImageUtils with EXIF stripping
- Accessibility: Added 'Take photo' label

* Full-screen camera with photo library option

- Change to fullScreenCover for immersive camera experience
- Add action sheet with 'Take Photo' and 'Choose from Library' options
- Renamed ImagePickerView to support both camera and library sources
- Both options open full-screen for better UX
- Updated accessibility label to 'Add photo' (more accurate)

* Fix camera white bars with overFullScreen presentation

- Changed modalPresentationStyle from .fullScreen to .overFullScreen
- This should eliminate white bars at top/bottom on notched devices
- Explicitly set showsCameraControls and cameraOverlayView for camera mode

* Gesture-based photo access: Tap for library, long-press for camera

UX improvements:
- Tap camera icon → Photo library (common use case)
- Long press camera icon (0.3s) → Direct camera (quick photos)
- Removed action sheet entirely for cleaner flow
- Power users can long-press for instant camera access

This is more discoverable and eliminates an extra step in the UI.

* Simplify camera presentation to reduce frame errors

- Changed back to standard .fullScreen presentation
- Removed overFullScreen which was causing frame dimension errors
- Let iOS handle safe areas automatically (white bars are intentional)
- Reduces gesture gate timeout warnings

Note: White bars on notched devices are iOS default behavior for
UIImagePickerController. This respects safe areas for status bar
and home indicator. True edge-to-edge would require custom AVFoundation
camera implementation.

* Force dark mode on camera/picker for black safe area bars

- Set overrideUserInterfaceStyle = .dark on UIImagePickerController
- Changes white bars to black (much better looking)
- Camera controls and photo library also appear in dark mode
- Consistent dark appearance regardless of system settings

* Optimize sheet presentation for camera UI

- Force .large detent for maximum height
- Hide drag indicator for cleaner look
- Use ignoresSafeArea to give camera full space
- Should show complete flash button and controls

* Fix P1: Add DoS protections to PeerID fragment handler

Critical security fix addressing Codex review feedback:

The PeerID overload of handleFragment (which is actually called by
CoreBluetooth) was missing key safety checks that existed in the
String overload:

1. Added total <= 10000 check to prevent unbounded fragment counts
2. Added cumulative size check against FileTransferLimits before
   storing each fragment
3. Prevents memory exhaustion DoS attacks via malicious fragment streams

This ensures the actually-used code path has proper bounds checking.

* Fix decompression size limit to support max-sized file transfers

Root cause: BinaryProtocol.decode() was rejecting decompressed payloads
larger than maxPayloadBytes (1 MB), but TLV-encoded file transfers are
slightly larger due to metadata overhead.

Fixes:
- Changed decompression limit from maxPayloadBytes to maxFramedFileBytes
- This accounts for TLV overhead (~50 bytes) + binary protocol headers
- Now allows ~1.12 MB decompressed payloads (1 MB + overhead budget)

The failing test was:
- Creating 1 MB file content
- TLV encoding adds ~50 bytes (1,048,627 total)
- Compression reduces to ~1,084 bytes (highly repetitive data)
- During decode, decompression was rejecting the 1,048,627 byte output
- Now correctly allows it since 1,048,627 < 1,179,760 (maxFramedFileBytes)

All 154 tests now pass including 'Max-sized file transfer survives reassembly'

* Fix critical thread-safety crash in PeerID fragment handler

CRITICAL: The PeerID version of _handleFragment was accessing
incomingFragments dictionary without collectionsQueue synchronization,
causing crashes when multiple BLE threads processed fragments concurrently.

Crash stack trace pointed to line 3431 (dictionary subscript) with:
'doesNotRecognizeSelector' - classic concurrent mutation crash.

Fix:
- Wrapped ALL incomingFragments/fragmentMetadata access in
  collectionsQueue.sync(flags: .barrier)
- Matches the thread-safe pattern used in String version
- Separate cleanup into its own barrier block after reassembly
- Prevents concurrent dictionary mutations from multiple BLE threads

This is the same pattern as the String version (line 1128) which didn't crash.

* Remove Localizable.xcstrings formatting noise

The Localizable.xcstrings file had massive formatting-only changes
(spacing: 'key' vs 'key :') that added 50K+ lines to the PR diff.

This was just Xcode reformatting with no actual string changes.

Reverted to main's version to keep PR focused on actual code changes.

* Add macOS photo picker support

- Added MacImagePickerView with NSOpenPanel for macOS
- macOS shows photo.circle.fill icon (no camera hardware)
- Opens native file picker for images (.png, .jpeg, .heic)
- Images processed through ImageUtils with EXIF stripping
- Simple sheet with Select/Cancel buttons

Cross-platform photo sharing now works:
- iOS: Tap for library, long-press for camera
- macOS: Tap for file picker

* Add Localizable strings for camera and voice features

Xcode auto-generated localization strings for new UI elements:
- Camera/photo picker labels
- Voice recording UI strings
- Media attachment descriptions

These are legitimate new strings needed for the audio+image feature,
not just formatting changes.

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
Co-authored-by: islam <2553451+qalandarov@users.noreply.github.com>
2025-10-18 20:55:33 +02:00
IslamandGitHub 551a843691 PeerID 18/n: BitchatDelegate + Tests (#769) 2025-10-07 16:01:53 +02:00
b5b05977fb Show Bluetooth permission alerts on launch and foreground (#765)
* Fix test suite peer ID collisions

Use unique peer IDs for each test suite to prevent global registry
collisions when Swift Testing runs suites in parallel.

- PrivateChatE2ETests: PRIV_* prefix
- PublicChatE2ETests: PUB_* prefix
- Update all peer ID references to use actual instance IDs

This fixes the race condition where simplePublicMessage() was receiving
duplicate deliveries due to registry contamination.

* Add Bluetooth permission & state alerts on launch and foreground

Wire up existing Bluetooth alert infrastructure to show notifications
when Bluetooth is off, unauthorized, or unsupported.

Changes:
- Add didUpdateBluetoothState() to BitchatDelegate protocol
- BLEService now notifies delegate when Bluetooth state changes
- ChatViewModel implements delegate method to show alerts
- Check Bluetooth state on app launch (after 100ms delay)
- Check Bluetooth state when app comes to foreground
- Add getCurrentBluetoothState() method to BLEService

The UI alert already existed but wasn't wired up. Now users will see
appropriate alerts for:
- Bluetooth turned off
- Bluetooth permission denied
- Bluetooth unsupported on device

Alert includes a button to open Settings on iOS.

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-10-06 22:47:11 +02:00
IslamandGitHub 01ec4573f8 Extract DeliveryStatusView into a separate file (#757) 2025-10-06 11:20:39 +02:00
IslamandGitHub 6a6504c6f2 Refactor: Extract types from BitchatProtocol (#611)
* Extract BitchatMessage into a separate file

* Convert `fromBinaryPayload` to `convenience init?`

* Extract message dedup into an extension

* Remove dead `formatMessageContent`

* Minor refactor of timestamp and username formatting

* Remove dead `getSenderColor`

* Extract MessagePadding into a separate file

* Extract BitchatPacket into a separate file

* Extract ReadReceipt into a separate file

* Extract NoisePayload into a separate file

* Remove unnecessary import
2025-09-15 15:21:03 +02:00
IslamandGitHub ea8d51a36b Refactor: BitchatMessage (#610)
* Extract BitchatMessage into a separate file

* Convert `fromBinaryPayload` to `convenience init?`

* Extract message dedup into an extension

* Remove dead `formatMessageContent`

* Minor refactor of timestamp and username formatting

* Remove dead `getSenderColor`
2025-09-15 15:00:12 +02:00
2ac01db9c4 SYNC_REQUEST 2 (#616)
* wip

* woohooo

* Plumtree gossip: don't subset REQUEST_SYNC fanout; make RequestSyncPacket.encode use const

* bloom -> gcs [wip]

* fix build

* fix broadcast

* prune old messages too

* faster sync

* prune better

* adjust parameters

* fix(sync): make cap a constant in GCSFilter.buildFilter to silence 'never mutated' warning

* fix(mesh): surface self-origin public messages recovered via sync; only ignore self when TTL != 0 in handleMessage

* sync: allow self messages via GCS restore and relax TTL==0 acceptance\n- Bypass dedup for self TTL==0 packets in handleReceivedPacket\n- Accept self TTL==0 in handleMessage and set nickname\n- Accept unknown senders for TTL==0 with anon# prefix to restore history

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-09-15 13:57:09 +02:00
IslamandGitHub e72fe50ffa Perf: Add final to classes that are not inherited (#574) 2025-09-11 19:17:04 +02:00
60b0deee7b Cleanup: remove dead code, normalize fingerprints, modernize share extension, trim test noise, and drop ‘preparing to share…’ message (#520)
* Remove dead code and artifacts: drop PeerManager, unused views/types; delete LegacyTestProtocolTypes; update .gitignore; purge TestResult.xcresult and build.log

* Tests: gate verbose prints under DEBUG; ChatViewModel: remove legacy fingerprint helper and rely on UnifiedPeerService

* Share Extension: migrate to UIKit + UTTypes; drop Social/SLComposeServiceViewController

* Remove 'preparing to share …' system message; send shared content immediately

* Inline comment cleanup: drop legacy 'removed' breadcrumbs across protocols, services, view model, and views

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-25 18:01:19 +02:00
5fd9140ffa QR verification: live challenge/response over Noise; persistence, offline badges, and UX/perf polish (#510)
* QR verification scaffold: add Noise verify payload types, VerificationService with QR schema/signing, placeholder MyQR/Scan views, and UI entry points in header

* QR: fix VerificationQR mutability (sigHex var) and remove duplicate Data hex helpers to resolve redeclaration; wire signed payload assembly

* QR: render actual QR images with CoreImage; add copy button; keep scanner placeholder for now

* QR: fix SwiftUI modifiers — apply .interpolation(.none) and .resizable() to platform Image inside ImageWrapper; remove from wrapper usage

* QR: add iOS camera scanner using AVFoundation; integrate into Scan view; add NSCameraUsageDescription to Info.plist

* QR: make NoisePayloadType exhaustive in ChatViewModel switches by ignoring verifyChallenge/verifyResponse for now (placeholder)

* QR verification: speed + persistence + UX

- Inject live Noise into VerificationService; prewarm QR on app start
- Keep camera active; remove intermediate responder toast
- One-shot/dupe guards and deferred send on handshake
- Persist verified status immediately; standardize fingerprint (SHA-256)
- Show verified badge for offline favorites; mutual verification toast
- VERIFY sheet styling to match peer sheet; UI polish
- Logs to diagnose verified load + favorites mapping

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-24 23:19:58 +02:00
jack c63350a4d3 UI: bold entire message text for self in mesh, DM, and geohash; adjust caching to include self flag 2025-08-21 02:51:14 +02:00
3074fa0fcb Refactor/repo hardening 01 (#462)
* BinaryProtocol: add optional padding control; BitchatPacket API for padded/unpadded bytes; BLEService: use unpadded encoding and remove ad-hoc unpadding on BLE writes

* BLEService: balance BLE padding — pad Noise handshake/encrypted frames; leave public/announce/leave unpadded; keep fragmentation consistent with chosen padding

* BLEService: replace Timer with DispatchSourceTimer on bleQueue; NostrTransport: cache placeholder NoiseEncryptionService to avoid reallocation

* Unify peerID validation: InputValidator handles 16-hex, 64-hex, or alnum-/_; NoiseSecurityValidator now delegates to InputValidator

* UI: use standard green for geohash toolbar badge and count (less bright in light mode)

* UI: standardize geohash sheet green to app standard (dark: system green, light: darker green) for buttons and checkmark

* Docs: align BinaryProtocol compression docs to zlib; Logs: reduce NostrTransport DELIVERED ack logs to debug to cut noise

* Tests: add InputValidator peerID coverage and BinaryProtocol padding round-trip/length tests

* Project: ensure Xcode project reflects new tests (references added)

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-20 13:29:53 +02:00
1c33a92765 Feature/signed public identity (#456)
* Require signed announces; add Ed25519 key/signature/timestamp TLVs and verify

- Protocol: AnnouncementPacket now requires ed25519PublicKey (0x03), announceSignature (0x04), and announceTimestamp (0x05). Encoder emits, decoder requires; unknown TLVs still tolerated.
- NoiseEncryptionService: add canonical announce sign/verify helpers using context 'bitchat-announce-v1'.
- BLEService: sign Announce, include TLVs; on receive verify (±5 min skew) and ignore unverified; store ed25519 key and isVerifiedNickname in PeerInfo.
- Preserve 8-byte on-wire IDs to keep BLE headers small; no per-message bloat.

* Fix Data.append usage for timestamp bytes in Packets and NoiseEncryptionService (use append(contentsOf:) on UnsafeRawBufferPointer)

* BLEService: fix non-optional announce fields and unwrap signature result; enforce required verification path

* Enforce verified-only public messages; append peerID suffix on nickname collisions in handleMessage

* Suffix duplicate nicknames with peerID prefix in snapshots and getPeerNicknames; ensures lists and messages disambiguate 'jack' vs 'jack'

* Include self nickname in collision detection: suffix remote 'jack' when it matches our nickname in lists and public chat

* UI labels: remove space before '#abcd' suffix in names (public chat, peer lists, snapshots)

* Style '#abcd' suffix light gray:
- Public chat: color suffix in sender via AttributedString segments
- People list: split name and color suffix segment; add helper splitNameSuffix()

* Debounce 'bitchatters nearby' notification: add 60s grace before reset when mesh goes empty; cancel reset when peers return

* Lighten '#abcd' suffix: use Color.secondary.opacity(0.6) in public chat sender and People list

* Toolbar peers indicator: use blue when Bluetooth peers present (was default text color)

* Toolbar peers indicator: use grey when zero peers (was red)

* Toolbar peers indicator: use system grey (Color.secondary) when zero peers, not green

* Fix crash: mutate peripherals dict on BLE queue (not main). Move scan restart to BLE queue as well.

* Reduce connect timeout churn: back off peripherals that time out (15s), increase timeout to 8s, skip non-connectable adverts, and demote timeout log to debug; clean backoff map periodically

* Mentions: support '@name#abcd' disambiguation; filter hashtag/URL styling inside mentions; deliver notifications only to the specified suffixed target when collisions exist

* Fix string interpolation in mention log (escape sequence)

* Mentions: parse '@name#abcd' in sender/receiver; render mention suffix grey (not orange/blue/underlined); ensure receiver notifications trigger for suffixed tokens

* Mentions: include own suffixed token 'name#<myIDprefix>' in valid tokens so '@name#abcd' to self is recognized and notified

* Public actions: show own system message by processing own public messages (remove early-return). Private /hug: add local system message for sender's chat.

* Grammar: change local '/hug' message to past tense ('you hugged/slapped'). Notifications: only fire 'bitchatters nearby' on rising-edge; remove 5-min re-fire and increase empty reset grace to 10m.

* Public /hug echo: add local system message so sender sees action immediately (no reliance on echo)

* Fix visibility: expose addPublicSystemMessage on ChatViewModel and use it from CommandProcessor

* use noise pubkey wip

* ttl=0 for signatures

* verification works

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-19 23:37:15 +02:00
a30b73dd99 Feature/fragmentation fixes (#453)
* Fix fragmentation + BLE long-write + padding

- Accumulate CBATTRequest long writes by offset and decode once per central
- Decode original packet after fragment reassembly (preserve flags/compression)
- Switch MessagePadding to strict PKCS#7 and validate before unpadding
- Make BinaryProtocol.decode robust: try raw first, then unpad fallback
- Unpad frames before BLE notify; fragment when exceeding centrals' max update length
- Skip notify path when max update length < 21 bytes (protocol minimum)

Verified large PMs and announces route without decode errors and peers show reliably.

* Tests: fix weak delegate lifetime, legacy constants, and unused vars; fragment unpadded frames

- BLEServiceTests: hold strong reference to MockBitchatDelegate
- IntegrationTests: fix inline comment braces; replace removed types with test-safe values; use numeric 0x06 for legacy handshake resp checks
- BinaryProtocolTests: remove unused minResult variable
- BLEService: fragment the unpadded frame so fragments are efficient

* tests: add Noise rehandshake recovery test; document in-memory test bus and autoFlood; stabilize large-network broadcast

* tests: align suite with current behavior (compression, padding, routing, nonce); deflake and stabilize

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-19 01:22:21 +02:00
6fbf7eee25 Refactor/ble nostr boundaries (#449)
* Refactor: move Nostr embedding and TLVs out of BLE; add NostrEmbeddedBitChat, Packets, PeerIDUtils; centralize MessageDeduplicator; update ChatViewModel to use new helpers; remove AI_CONTEXT.md and CLAUDE.md

* Rename class to BLEService with compatibility alias; move mention parsing out of BLE; emit low-level BLE events to delegate; unify hex helpers; accept 64-hex in isPeerConnected; add PeerIDResolver

* Project: rename file to BLEService.swift and update Xcode project; keep typealias SimplifiedBluetoothService = BLEService for compatibility

* Remove SimplifiedBluetoothService alias; update app code to use BLEService explicitly

* Tests: rename MockSimplifiedBluetoothService to MockBLEService; update typealiases and Xcode project

* Docs: update comments to refer to BLEService (tests, protocol, noise service)

* Tests: rename SimplifiedBluetoothServiceTests to BLEServiceTests; update project references and class names

* Introduce Transport protocol; BLEService conforms; document delegate-only event pattern in BLEService; keep publishers internal for UnifiedPeerService

* Adopt Transport end-to-end: add TransportPeerSnapshot + publishers; BLEService maps to Transport snapshots; UnifiedPeerService consumes Transport; ChatViewModel holds Transport

* Fix Transport integration: replace getPeerFingerprint with getFingerprint(for:); update PrivateChatManager and CommandProcessor to use Transport; add BLEService.getFingerprint(for:); update PeerManager to use Transport

* Refactor transport and BLE/Nostr layers; unify UI events; fix MainActor isolation

- Rename SimplifiedBluetoothService to BLEService and slim responsibilities
- Introduce Transport protocol and peerEventsDelegate for UI updates
- Add NostrTransport and MessageRouter to route PM/read/favorite via BLE or Nostr
- Centralize TLVs, PeerID utils, and MessageDeduplicator outside BLE
- Update UnifiedPeerService and ChatViewModel to use Transport and delegate events
- Fix MainActor isolation: route delegate calls via Task on MainActor; update notifyUI helper
- Adjust related files and tests accordingly

* BLEService: remove internal publishers; switch to delegate-only events

- Drop legacy messages/peers/fullPeers publishers
- Provide lightweight peerSnapshotSubject only to satisfy Transport
- Rework publishFullPeerData to build snapshots from internal state and notify delegate + subject
- Remove all peersPublisher.send call sites
- Keep UnifiedPeerService on delegate updates exclusively

* Remove inlined Nostr send helpers from ChatViewModel; route via MessageRouter

- Replace direct Nostr sends (PM, ACKs, favorites) with MessageRouter
- Add router method for delivery ACKs and implement NostrTransport.sendDeliveryAck
- Simplify ChatViewModel favorite notification path to use router
- Keep Nostr receive handling intact; reduce duplication

* Fix ReadReceipt initializer usage in ChatViewModel (readerID + readerNickname)

* Fix unused variable warning: replace shadowed 'nostrPubkey' bind with boolean check in ChatViewModel

* Fix queued PM format: use TLV for pending messages after Noise handshake

- Pending messages (including first-time favorite notifications) now use the same TLV encoding as normal sends
- Ensures ChatViewModel can decode on first send, even if handshake completes after queuing

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-17 15:17:04 +02:00
845ffc601b Refactor/robustness (#446)
* Refactor BitChat for improved robustness and performance

Major refactoring to simplify architecture and fix critical issues:

Architecture Improvements:
- Replace complex BluetoothMeshService with simplified SimplifiedBluetoothService
- Consolidate message routing and peer management into unified services
- Remove redundant caching layers and optimize performance

Bug Fixes:
- Fix critical BLE peer mapping corruption in mesh networks
- Fix encrypted message routing failures in multi-peer scenarios
- Fix app freezes and Main Thread Checker warnings
- Fix BLE message delivery in dual-role connections
- Fix favorite toggle UI not updating instantly
- Fix Nostr offline messaging with 24-hour message filtering

Features:
- Add command processor for chat commands
- Add autocomplete service for mentions and commands
- Improve private chat management with dedicated service
- Add unified peer service for consistent state management

Performance:
- Optimize BLE reconnection speed
- Reduce excessive logging throughout codebase
- Improve message deduplication efficiency
- Optimize UI updates and state management

* Improvements refactor robust (#441)

* remove unused code

* remove more

* TLV for announcement

* restore

* restore

* restore?

* messages tlv too (#442)

* Fix Nostr notification and read receipt issues, add TLV encoding, cleanup unused code

## Notification & Read Receipt Fixes
- Fixed toolbar notification icon appearing incorrectly on app restart for already-read messages
- Fixed read receipts being incorrectly deleted on startup when privateChats was empty
- Fixed messages not being marked as read when opening chat for first time
- Fixed senderPeerID not being updated during message consolidation
- Added startup phase logic to block old messages (>30s) while allowing recent ones
- Fixed unread status checking across all storage locations (ephemeral, stable Noise keys, temporary Nostr IDs)

## TLV Encoding Implementation
- Implemented Type-Length-Value encoding for private message payloads
- Added PrivateMessagePacket struct with TLV encode/decode methods
- Enhanced message structure for better extensibility and robustness

## Code Cleanup
- Removed unused PeerStateManager class and related dependencies
- Removed dead protocol types (DeliveryAck, ProtocolAck/Nack, NoiseIdentityAnnouncement)
- Cleaned up BitchatDelegate by removing unused methods
- Removed excessive debug logging throughout ChatViewModel
- Added test-only ProtocolNack helper for integration tests

## Technical Details
- Messages stored under three ID types: ephemeral peer IDs, stable Noise key hexes, temporary Nostr IDs
- Fixed cleanupOldReadReceipts() to skip when privateChats is empty or during startup
- Updated message consolidation to properly update senderPeerID
- Restored NIP-17 timestamp randomization (±15 minutes) for privacy

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com>
2025-08-17 01:51:54 +02:00
7a7c89e689 Remove protocol versioning and handshake logic (#433)
Simplified the protocol by removing version negotiation and handshake sequences.
All devices now use protocol version 1 without negotiation. This eliminates
unnecessary connection overhead and complexity while maintaining full
compatibility across the network.

Changes:
- Removed versionHello and versionAck message types
- Simplified connection flow to use announce packets only
- Removed version negotiation state tracking
- Cleaned up handshake timeout logic
- Reduced connection establishment overhead

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-12 02:24:34 +02:00
8f32edaa64 Security fixes and improvements (#374)
- Fix force unwrapping in NostrIdentity bech32 functions that could crash on non-ASCII input
- Add comprehensive input validation for all protocol messages (peer IDs, nicknames, timestamps)
- Strengthen keychain security with better sandbox detection and consistent app group usage
- Implement secure memory clearing for cryptographic keys and shared secrets
- Fix panic mode not reconnecting to mesh by restarting services after emergency disconnect

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-07-31 23:42:08 +02:00
a97d5c2d5e Implement Nostr NIP-17 for offline messaging and performance optimizations (#358)
* Implement Nostr NIP-17 integration for offline mutual favorite messaging

- Add Nostr relay connectivity and NIP-17 gift-wrapped private messages
- Implement dual transport system: Bluetooth mesh + Nostr relays
- Add favorites persistence with mutual detection and Nostr key exchange
- Support offline messaging for mutual favorites via Nostr relays
- Handle peer identity rotation with automatic favorite key updates
- Fix UI to show all favorites (online and offline) in peer list
- Add proper message routing based on peer availability
- Update peer list icons: 📶 for mesh, 🌐 for Nostr, 🌙 for one-sided
- Fix toolbar display for offline peers in private chat view
- Add network entitlements for macOS and iOS
- Implement automatic noise key updates when peers reconnect

* Implement Nostr NIP-17 for private messaging between mutual favorites

- Add support for NIP-17 gift-wrapped private messages with double encryption
- Enable private messaging via Nostr when mutual favorites are offline
- Fix peer reconnection issues: users now stay in private chat when peer reconnects
- Fix read receipt delivery: send pending receipts when peer comes back online
- Add message ID tracking through Nostr transport for proper delivery acknowledgments
- Update peer noise key mapping when peers reconnect with different IDs
- Check for Nostr messages when app becomes active
- Implement 7-day message retrieval window for better reliability

* Fix private message UI refresh and adjust PEOPLE header spacing

- Fix UI not updating when receiving private messages on mesh
  - Add immediate batch processing for messages in active chat
  - Force UI update when viewing current chat peer
  - Ensure real-time message display without navigation
- Reduce PEOPLE header spacing from 16 to 12 points for tighter UI

* Fix build errors and unused value warnings in Nostr favorites integration

* Implement read receipts via Nostr

- Added sendReadReceipt method to MessageRouter to send receipts via mesh or Nostr
- Added handleReadReceipt to process incoming read receipts from Nostr
- Made ReadReceipt.readerID mutable to allow updates
- Added missing notification names and error cases
- Uncommented and enabled read receipt handling in ChatViewModel
- Read receipts now work seamlessly via both mesh and Nostr transports

* Fix ReadReceipt initialization - use correct constructor

* Implement persistent message deduplication for Nostr

- Added ProcessedMessagesService to track messages across app restarts
- Store processed message IDs and last timestamp in UserDefaults
- Skip already processed messages when receiving from Nostr
- Adjust subscription filter to use smart timestamp (last processed or 24h)
- Prevents duplicate messages when reconnecting to Nostr relays

* Fix peer list UI not updating to Nostr mode on disconnect

- Remove peer from peerNicknames when connection state changes to disconnected
- Ensures UI properly reflects peer disconnection state
- Peer list now correctly shows Nostr mode (🌐) when peer walks out of range

* Update peer count to include Nostr peers and improve UI indicators

- Peer count now shows total peers including those available via Nostr
- Count appears purple when only Nostr peers are connected
- Private message header shows purple globe icon for Nostr transport
- Consistent visual language for Nostr connectivity across the app

* Improve RSSI real-time updates and fix UI flashing

- Reduce RSSI update timer from 10s to 5s and per-peripheral from 5s to 3s
- Add RSSI change detection with 2 dBm threshold for responsive updates
- Always update previous RSSI values to fix gradual change detection bug
- Trigger RSSI read on peer authentication for immediate status
- Fix UI flashing 'nobody around' by removing array clearing on updates
- Add proper cleanup of RSSI tracking on disconnect and peer rotation

* Fix favorite nickname updates and peer list filtering

- Add updateNickname method to FavoritesPersistenceService to update nicknames while preserving favorite status
- Update announce handler to check for existing favorites and update their nicknames
- Remove dead BluetoothMeshService+PublicAPI.swift file
- Move sendFavoriteNotification to main BluetoothMeshService
- Fix peer list to only show connected peers and user's favorites (not peers who favorite the user)
- Remove UI logic for showing peers who favorite us but we don't favorite back

* Remove dead code and fix ghost connections

Phase 1 - Remove abandoned peer ID rotation code:
- Remove previousPeerID property and rotationGracePeriod constant
- Remove grace period logic from isPeerIDOurs()
- Remove previousPeerID handling from announce packets
- Pass nil for previousPeerID in identity announcements

Phase 2 - Fix ghost connections from relayed packets:
- CRITICAL FIX: Only add peers to activePeers if they have a peripheral connection
- Check for peripheral connection before marking peer as active
- Prevents ghost connections when announce packets are relayed
- Log warning when rejecting relayed announce without peripheral

Phase 3 - Begin consolidating redundant peer tracking:
- Create new PeerSession class to unify peer data in one place
- Add helper methods for PeerSession management
- Integrate PeerSession into announce packet handling
- Update authentication state changes to use PeerSession
- Update peripheral mapping and RSSI to sync with PeerSession
- Update disconnect and leave handling to update PeerSession
- Add consolidated getter methods for peer info

This fixes the issue where peers appeared connected without actually having a Bluetooth connection, and begins the migration to a cleaner single-source-of-truth peer tracking system.

* Fix multiple connect messages on peer restart

- Move hasPeripheralConnection check outside sync block to fix scope issue
- Add debug logging to track connect message conditions
- Ensure connect messages only show on first connection or reconnection with peripheral

* Optimize RSSI updates for better battery life

- Add app state tracking to BluetoothMeshService
- Only update RSSI when app is in foreground and peer list is visible
- Add setPeerListVisible method to control RSSI updates
- Remove individual periodic RSSI updates in favor of centralized timer
- Update ContentView to notify mesh service of peer list visibility changes
- Improve battery efficiency by avoiding unnecessary RSSI reads

* Initialize peer list visibility state on view appear

- Ensure RSSI timer state is properly initialized when view loads
- Call setPeerListVisible with initial showSidebar value

* Fix duplicate peers and multiple disconnect messages

- Fixed duplicate peer entries when relay-connected by adding relay-connected peers to connectedNicknames set
- Added deduplication logic for disconnect messages with 2-second window to prevent multiple disconnect notifications for same peer
- Added cleanup for old disconnect notification tracking to prevent memory growth

* Fix peer count indicator color logic

- Show green for any mesh peer (direct Bluetooth or relay connected)
- Show purple only for Nostr-only peers (no mesh connections)
- Show red only when no peers are reachable at all
- Fixed to use meshPeerCount instead of viewModel.isConnected which only checked direct connections

* Fix relay connection issues and peripheral mapping cleanup

- Fixed relay-connected peers being marked as directly connected when receiving identity announce
- Added proper cleanup of temp peripheral mappings when discovering real peer ID
- Fixed disconnect notification deduplication cleanup
- Improved debug logging to show actual connection state (direct/relay/nostr/offline)
- Added debug logging for relay connection detection
- Fixed compiler warning about unused variable

* Fix Unknown peer disconnect notifications and disable faulty relay detection

- Add check to prevent disconnect notifications for Unknown peers that never announced
- Disable relay connection detection until proper relay tracking is implemented
- In a 2-peer network, peers should never show as relay-connected

* Fix RSSI updates and peer visibility after reconnection

- Add updatePeers() call in didUpdatePeerList to refresh RSSI values in UI
- Track version hello times to better detect direct connections
- Allow peers to be marked active if recent version hello received
- Fix thread safety for version hello tracking
- Clean up old version hello times to prevent memory leaks

* Remove RSSI tracking completely and replace with radio icon for mesh connections

* Fix build errors after RSSI removal

- Add missing peripheralID declaration in didDiscover delegate method
- Remove obsolete setPeerListVisible calls from ContentView

* Center private message header elements using ZStack layout

- Replace HStack with ZStack for perfect centering
- Globe/nick/lock cluster now always centered regardless of button sizes
- Back and favorite buttons positioned in overlay HStack

* Fix private chat view showing Unknown when peer reconnects with new ID

- Update FavoritesPersistenceService to notify with both old and new keys
- Handle peer ID changes in ChatViewModel to migrate private chat data
- Update selectedPrivateChatPeer when favorite's noise key changes
- Maintain chat history and unread status across peer ID changes

* Fix read receipts after peer reconnection and replace nos.lol relay

- Updated sendReadReceipt to resolve current peer ID when peers reconnect with new IDs
- Enhanced MessageRouter to check favorites for current noise keys
- Replaced nos.lol relay with relay.snort.social to avoid PoW requirements

* Fix message routing to use Nostr when peers are disconnected

Changed message routing logic to check actual peer connection status using
isPeerConnected() instead of just checking if peer exists in nickname list.
This ensures that offline mutual favorites correctly route messages through
Nostr instead of attempting Bluetooth handshakes.

Also added safety check to prevent starting private chat with ourselves.

* Add debug logging for Nostr timestamp randomization

Added logging to track the random offset being applied to Nostr event
timestamps to debug why messages appear 8-9 minutes in the future.

* Fix Nostr timestamp issue by reducing randomization range

Temporarily reduced the timestamp randomization from +/-15 minutes to +/-1 minute
to address messages appearing 8-9 minutes in the future. Added detailed UTC/local
time logging to help debug the issue.

The random offset should have been evenly distributed but was consistently
showing positive offsets. This change mitigates the issue while we investigate
the root cause.

* Fix message routing for offline favorites and reduce Nostr timestamp randomization

- Fix transport selection to properly detect disconnected peers using isPeerConnected()
- Change from checking peer nicknames to checking actual connection status
- Reduce Nostr timestamp randomization from ±15 minutes to ±1 minute
- Add detailed timestamp logging for debugging

* Improve PM header UI and encryption status display

- Show transport icons (radio/link/globe) in PM header matching peer list
- Always show lock icon if noise session ever established (no handshake icon)
- Change verified icon from shield to checkmark seal
- Use consistent green color (textColor) for PM header and encryption icons

* Update AI_CONTEXT.md with comprehensive Nostr implementation details

- Add Nostr and MessageRouter to architecture diagram
- Document NIP-17 gift wrap implementation
- Explain favorites integration and mutual requirement
- Detail message routing logic and transport selection
- Add security considerations and debugging tips
- Update common tasks with Nostr-specific guidance

* Fix data consistency issues in favorites, chat migration, and bloom filter

- Fix favorites deduplication to use public key instead of nickname
  Prevents losing favorites when multiple peers use same nickname

- Fix private chat migration to use fingerprints instead of nicknames
  Prevents merging unrelated conversations that share nicknames
  Fallback to nickname matching only for legacy data without fingerprints

- Fix bloom filter reset to preserve messages from last 10 minutes
  Prevents duplicate message processing after bloom filter resets
  Keeps processedMessages for 10 minutes while bloom filter resets every 5

* Add mutual favorites internet messaging to app info

* Remove excessive debug/info logging for production readiness

- Removed ~140 debug/info level logs across core services
- Preserved critical logs: errors, warnings, security events, state changes
- Kept logs for: peer join/leave, favorite status, mutual relationships
- Cleaned up verbose logging in: Bluetooth mesh, Nostr, message routing
- Improved performance by reducing log I/O overhead

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Implement performance optimizations and fix build warnings

- Add UI update debouncing (50ms) to prevent excessive SwiftUI refreshes
- Implement memory bounds for processedMessages with LRU eviction
- Add encryption queue cleanup for disconnected peers
- Optimize peer lookups from O(n) to O(1) with indexed dictionary
- Fix multiple compiler warnings (unused variables, missing break statements)
- Optimize peer counting with single-pass reduce operation
- Fix ViewBuilder control flow issue in ContentView
- Fix Dictionary initialization type mismatches with Array wrapper

* Add TTL-based cleanup for Noise handshake sessions

- Add session TTL (5 minutes) and max session limit (50) to NoiseHandshakeCoordinator
- Clean up old established sessions to prevent unbounded memory growth
- Move handshake cleanup timer out of DEBUG conditional for production use
- Run cleanup every 60 seconds in production (vs 30s in debug)
- Clean up crypto state immediately on peer disconnect
- Prevents memory leaks from accumulating Noise sessions

* Pre-compute and store fingerprints in PeerSession for O(1) lookups

- Store fingerprint in PeerSession when peer authenticates
- Update getPeerFingerprint() and getFingerprint() to check PeerSession first
- Replace all noiseService.getPeerFingerprint() calls with optimized version
- Eliminates repeated SHA256 calculations during message processing
- Improves performance for favorite checks and encryption status updates

* Implement exponential backoff for Nostr relay connections

- Add reconnection tracking fields to Relay struct (attempts, timing)
- Replace fixed 5-second delay with exponential backoff (1s → 2s → 4s... max 5min)
- Stop reconnection attempts after 10 failures to prevent infinite retries
- Reset attempt counter on successful connection
- Add utility methods: retryConnection(), getRelayStatuses(), resetAllConnections()
- DNS failures still bypass retry logic as before
- Improves battery life and reduces server load from constant reconnection attempts

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-07-30 23:14:17 +02:00
4867ddca0d Add comprehensive AI-friendly documentation across core files (#328)
- Created AI_CONTEXT.md as central documentation hub for AI assistants
- Added detailed file-level documentation to all major components
- Documented architecture, design decisions, and security considerations
- Added usage examples and integration guidance
- Improved code discoverability with clear component descriptions

Documentation covers:
- BluetoothMeshService: Core networking and mesh protocol
- BitchatProtocol: Application-layer protocol design
- NoiseProtocol: Cryptographic implementation details
- ChatViewModel: Business logic and state management
- IdentityModels: Three-layer identity architecture
- NoiseEncryptionService: High-level encryption API
- SecureIdentityStateManager: Secure persistence layer
- BinaryProtocol: Low-level wire format

This documentation will significantly improve AI understanding of the codebase structure and enable faster, more accurate assistance with development tasks.

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-07-27 10:18:47 +02:00
54c7eba8cb Improve code organization and documentation (#325)
* Add MARK headers to improve code organization in major files

* Reorganize peer management functions in BluetoothMeshService

- Removed duplicate getCurrentPeerID(for:) function
- Consolidated peer identity functions in Peer Identity Mapping section
- Moved getPeerFingerprint(), getFingerprint(for:), isPeerIDOurs() to proper location
- Moved getCurrentPeerIDForFingerprint() and getCurrentPeerIDs() from Message Sending section
- Moved notifyPeerIDChange() to Peer Management section

* Consolidate peer management functions in BluetoothMeshService

- Moved getCachedPublicKey() and getCachedSigningKey() from Identity Cache Methods to Peer Connection Management
- Moved getPeerNicknames() and getPeerRSSI() to Peer Connection Management section
- Moved getAllConnectedPeerIDs(), notifyPeerListUpdate(), and cleanupStalePeers() to Peer Connection Management
- Removed duplicate function declarations after consolidation
- Improved code organization by grouping all peer-related functions together

* Consolidate message handling functions in ChatViewModel

- Moved handleHandshakeRequest() from floating location to Message Reception section
- Moved trimMessagesIfNeeded() and trimPrivateChatMessagesIfNeeded() to Message Batching section
- Improved code organization by grouping related message handling functions together
- Removed unnecessary comments from trim functions

* Improve ContentView organization with better documentation

- Added descriptive comments for complex inline computations
- Documented message extraction logic for private vs public chats
- Documented peer data computation and sorting logic
- Improved code readability by explaining complex operations inline
- Note: Attempted to extract complex computations into helper functions, but SwiftUI scope limitations made inline documentation a better approach

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-07-26 00:11:23 +02:00
jack 0e78341102 Trim whitespace from nicknames to prevent display issues
- Added didSet observer to nickname property to trim on every change
- Trim nickname when loading from UserDefaults
- Update validateAndSaveNickname to properly trim
- Trim received nicknames in announce packets
- Add custom init/decoder for NoiseIdentityAnnouncement to ensure trimming
- Trim nicknames when decoding from binary data
2025-07-25 20:29:50 +02:00
3513228736 Implement handshake request notifications for pending messages (#321)
- Add handshakeRequest packet type (0x25) to notify recipients about queued messages
- Create HandshakeRequest struct with binary encoding for efficient transmission
- Send handshake requests when messages are queued due to missing session
- Display notifications when someone wants to send messages
- Fix verification persistence bug by adding forceSave on app termination
- Update UI to handle optional encryption icons (hide when no handshake attempted)

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-07-25 14:55:26 +02:00
809e222a31 Improve BLE connection stability and message reliability (#318)
* Remove sequence numbers from protocol

- Remove sequenceNumber field from BitchatPacket struct
- Update BinaryProtocol to not encode/decode sequence numbers (header size reduced from 17 to 13 bytes)
- Replace sequence-based duplicate detection with content-based using packet ID hash
- Update packet ID generation to use SHA256(senderID + timestamp + type + payload prefix)
- Remove all sequence tracking variables and methods
- Simplify duplicate detection to rely on timestamp and content hashing

* Fix connection stability issues

- Increase peer availability check interval from 5 to 15 seconds
- Fix availability logic to not mark connected peers as unavailable
- Add BLE connection keepalive timer (20s) to prevent iOS timeouts
- Fix missing delivery ACKs by passing peripheral context through Noise decryption
- Reduce identity announce frequency from 2 to 10 seconds minimum
- Remove unnecessary identity announces on connection
- Debounce identity cache keychain saves (2 second delay)
- Add message retry notification handler in ChatViewModel
- Fix version negotiation redundancy by checking existing negotiations
- Keep Noise sessions for already-connected peers

* Fix build errors in message retry handler

- Fix reference to 'displayedMessages' - should be 'messages'
- Fix sendMessage call signature to use individual parameters instead of message object
- Both iOS and macOS builds now succeed

* Fix remaining connection stability issues

- Fix duplicate identity announces with content-based deduplication
- Simplify peripheral mapping with cleaner temp ID to peer ID transitions
- Improve graceful leave detection across peer ID rotations
- Track previousPeerID from announcements to maintain state
- Add time-based cleanup for gracefully left peers

* Fix connection stability issues

- Add special duplicate detection for identity announces
- Simplify peripheral mapping with dedicated structure
- Improve graceful leave detection with peer ID rotation handling
- Track graceful leave timestamps for cleanup
- Transfer states properly during peer ID rotation

* Improve BLE connection stability and message reliability

- Increase peer availability timeout from 5s to 15s to prevent flapping
- Add BLE keepalive timer with 30s interval to maintain connections
- Fix missing delivery ACKs by passing peripheral context through decryption
- Reduce identity announce frequency from 2s to 10s minimum interval
- Add keychain save debouncing with 2s delay to prevent excessive writes
- Implement message retry system for failed deliveries to favorites
- Fix version negotiation redundancy by checking existing state
- Add special duplicate detection for identity announcements
- Implement graceful leave detection with peer ID rotation support
- Simplify peripheral mapping to reduce complexity
- Fix switch statement structure issues causing build errors

These changes significantly improve connection stability, eliminate peer availability flapping, and ensure reliable message delivery.

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-07-25 02:40:51 +02:00
492f90edd5 Optimize BLE mesh network for robustness and range (#314)
- Fixed relay probability calculation for 2-node networks (0% relay needed)
- Added protocol ACKs to prevent unnecessary retransmissions
- Implemented MessageState for enhanced duplicate detection
- Added exponential backoff for collision avoidance
- Fixed duplicate sends for bidirectional connections
- Resolved packet ID generation issues using immutable fields only
- Implemented smart rate limiting with progressive throttling
- Removed unnecessary debug logging and fixed build warnings
- Optimized message routing to prevent flooding in small networks

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-07-24 19:49:37 +02:00
jack f45c52e9d3 Optimize UI performance with message caching and List view
- Convert BitchatMessage from struct to class for efficient caching
- Cache formatted AttributedStrings to avoid expensive regex on every render
- Replace ScrollView+LazyVStack with native List for better cell reuse
- Implement message windowing (show last 100 messages for performance)
- Add LazyLinkPreviewView that defers loading for 0.5s to improve scroll performance

These optimizations significantly improve scroll performance, especially with large message lists.
2025-07-24 12:38:31 +02:00
jack a84d6f22ef Fix handshake deadlock after decryption failure
Always accept handshake initiations even with valid sessions, as the peer must have cleared their session for a good reason (e.g., decryption failure). This prevents deadlock where one peer has no session while the other maintains an invalid one.
2025-07-23 18:22:39 +02:00
jack f53e163d25 Remove all channel functionality and clean up test suite
- Remove channel UI elements from ContentView
- Remove channel data structures and methods from ChatViewModel
- Remove channel commands (/j, /leave, /channels)
- Remove channel field from BitchatMessage protocol
- Remove channel message types and handling
- Remove NoiseChannelEncryption.swift entirely
- Clean up all channel references across the codebase
- Fix compilation warnings (var to let conversions)
- Remove all outdated test files that used incorrect APIs
- Simplify app to only support public broadcast and 1:1 private messages
2025-07-23 01:33:54 +02:00
jack 5e726f993e Fix Noise handshake failures and implement binary protocol migration
- Fix asymmetric handshake state causing message delivery failures
- Prevent duplicate handshake init messages from disrupting ongoing handshakes
- Add defensive copying to all binary decoders to prevent thread safety issues
- Implement binary encoding for all 9 message types (60-80% bandwidth reduction)
- Fix delivery ACK decoding for Noise encrypted messages
- Add comprehensive logging for debugging handshake and message flow
- Fix race condition in delivery status updates
- Add relay logic for handshake packets to ensure mesh delivery
- Maintain backward compatibility with JSON fallback
2025-07-22 14:52:33 +02:00
jack 7579612c61 Migrate protocol from JSON to binary encoding
This change introduces a comprehensive binary protocol to replace JSON encoding
for all network messages, resulting in ~70% bandwidth reduction and 10-20x
faster parsing.

Key changes:
- Add BinaryEncodingUtils with common binary encoding/decoding operations
- Implement toBinaryData/fromBinaryData for all 9 message types
- Maintain backward compatibility with JSON fallback
- Add safety checks including minimum size validation and data copying
- Fix thread safety issues with concurrent data access
- Update all message handlers to try binary first, then JSON

Benefits:
- Reduced bandwidth usage (critical for Bluetooth)
- Faster message parsing
- Better MTU efficiency
- Eliminates JSON injection vulnerabilities
- Consistent binary format throughout the protocol

The implementation maintains full backward compatibility - new messages are
sent as binary while the app can still receive and process JSON messages
from older clients.
2025-07-22 14:12:39 +02:00
jack ce6e90701c Remove dead code and placeholders
- Remove NoisePostQuantum.swift entirely (placeholder with no implementation)
- Remove Double Ratchet placeholder code from NoiseChannelKeyRotation.swift
- Remove NoisePostQuantumTests that tested mock implementations
- Handle TODO for version negotiation rejection (now properly disconnects)
- Remove legacy comment about removed message type 0x02
- Keep deprecated ownerID field as it's still used for compatibility

This cleanup removes ~400 lines of placeholder code that was not
being used and unlikely to be implemented in the near future.
2025-07-22 11:20:07 +02:00
jack 83a808fce6 Implement Ed25519 signatures for identity announcements
- Add Ed25519 signing key pair to NoiseEncryptionService
- Update NoiseIdentityAnnouncement to include signingPublicKey
- Replace HMAC signatures with proper Ed25519 signatures
- Fix timestamp synchronization between signing and verification
- Add signature verification in PeerIdentityBinding
- Persist signing keys in keychain alongside Noise static keys

This provides cryptographic non-repudiation for peer identity claims
and strengthens the security of the identity rotation mechanism.
2025-07-22 10:50:47 +02:00
jack b61904bee9 Remove message retention and /save command
- Delete MessageRetentionService.swift
- Remove retentionEnabledChannels from ChatViewModel
- Remove /save command handling
- Remove retention UI elements from ContentView
- Remove channelRetention message type from protocol
- Update documentation and tests
2025-07-16 15:59:38 +02:00
jack 3fb39b8a30 Add protocol version negotiation for future compatibility
- Add version negotiation messages (0x20 versionHello, 0x21 versionAck)
- Implement VersionHello and VersionAck message types with platform info
- Add ProtocolVersion struct for version management and negotiation
- Update BinaryProtocol to check supported versions
- Add version negotiation to connection flow before Noise handshake
- Maintain backward compatibility with legacy peers (assume v1)
- Add comprehensive test suite with 40+ test cases
- Update documentation with version negotiation details

This ensures BitChat clients can negotiate protocol versions for smooth
upgrades while maintaining full backward compatibility with existing clients.
2025-07-15 14:33:37 +02:00
jack 3070a4d307 Implement Noise Protocol Framework and peer ID rotation for enhanced security and privacy
This major update replaces the basic encryption with the Noise Protocol Framework
and adds ephemeral peer ID rotation for enhanced privacy.

Key Changes:

Security Infrastructure:
- Implemented Noise Protocol Framework (XX handshake pattern)
- End-to-end encryption with forward secrecy and identity hiding
- Session management with automatic rekey support
- Channel encryption with password-derived keys

Privacy Enhancements:
- Ephemeral peer ID rotation (5-15 minute random intervals)
- Persistent identity through public key fingerprints
- Favorites and verification persist across ID rotations
- Block list based on fingerprints, not ephemeral IDs

Core Components Added:
- NoiseEncryptionService: Main encryption service
- NoiseSession: Individual peer session management
- NoiseChannelEncryption: Password-protected channel support
- SecureIdentityStateManager: Persistent identity storage
- FingerprintView: Visual fingerprint verification UI

Bug Fixes:
- Fixed handshake storm with tie-breaker mechanism
- Fixed missing connect messages during peer rotation
- Fixed delivery ACK compression issues
- Fixed race conditions in message queue
- Fixed nickname resolution for rotated peer IDs

Testing:
- Comprehensive test suite for Noise implementation
- Security validator tests
- Channel encryption tests
- Identity persistence tests
- Rate limiter tests

Documentation:
- BRING_THE_NOISE.md: Technical implementation details
- Updated WHITEPAPER.md: Simplified and focused on core innovations
- Removed temporary debug documentation

The implementation maintains backward compatibility while significantly
improving security and privacy. All existing features (channels, private
messages, favorites, blocking) work seamlessly with the new system.
2025-07-15 13:15:31 +02:00
jack 9794f3ebdc UI improvements and rename rooms to channels
- Changed system messages from green to grey with consistent 12pt font
- Fixed text wrapping to flow naturally under timestamps
- Changed default nickname to anonXXXX format
- Replaced text with icon representations in status bar
- Added icons to sidebar section headers
- Made autocomplete UI consistent between commands and @mentions
- Added welcome message for new users (3 second delay)
- Changed sidebar header to 'YOUR NETWORK'
- Added command aliases (/join, /msg)
- Implemented /hug and /slap commands with haptic feedback
- Improved command help display with alphabetization
- Renamed 'rooms' to 'channels' throughout entire codebase
2025-07-08 01:42:35 +02:00
jack e2b0632879 Add read receipts for private messages
- Added ReadReceipt structure and .readReceipt message type
- Added .read delivery status with blue checkmarks in UI
- Send read receipts when viewing a private chat
- Send read receipts immediately for new messages if chat is open
- Update message status from delivered to read when receipt received
2025-07-06 21:49:56 +02:00
jack 78cb8b1039 Fix delivery confirmation for private messages
- Pass message ID from ChatViewModel to BluetoothMeshService
- Preserve original message ID when creating ACK messages
- Move delivery tracking to ChatViewModel for consistent IDs
- Update project.yml to match current project structure
2025-07-06 21:25:41 +02:00
jack 1f890b00ac Add room-wide mandatory retention, update UI formatting, and documentation
- Implement room-wide message retention controlled by room owners
- Change username format from <name> to <@name> throughout UI
- Fix text alignment in chat messages (consistent font sizes)
- Add comprehensive technical whitepaper with Mermaid diagrams
- Update README with current features and commands
- Add retention status indicators and announcements
- Update command help text to use short versions (/j, /m)
2025-07-05 19:35:37 +02:00
jack 7151896102 feat: enhance password-protected rooms with key commitments and management
- Add key commitment scheme for immediate password verification
- Implement ownership transfer with /transfer command
- Add password change functionality with /pass command
- Include room metadata in initialization messages
- Remove /help command and rename /changepass to /pass
- Make room names tappable to show sidebar
- Remove spaces in person/room counter display
- Update UI to show lock icons and orange colors for protected rooms
- Fix password verification to work with empty rooms
- Add comprehensive tests for new functionality

This update significantly improves the security and usability of
password-protected rooms by allowing immediate verification without
waiting for encrypted messages.
2025-07-05 19:35:37 +02:00
jack 8d553adc0c Implement password-protected rooms with encryption
- Room creators can set/remove passwords for their rooms
- Passwords are used to derive encryption keys via PBKDF2
- All messages in password-protected rooms are encrypted with AES-GCM
- Room protection status is announced to all peers
- Password and room data persists across app launches
- Visual lock indicators for password-protected rooms
- Password prompts when joining protected rooms
- Only room creators can modify password settings
- Encrypted messages show placeholder text if password is unknown
2025-07-05 19:35:37 +02:00
jack 4dec23e216 Implement proper room leave notifications and improve UI
- Send leave notifications when users exit rooms
- Update room member lists when peers leave rooms
- Change current user icon from dot to person.fill
- Handle room-specific leave messages via protocol
- Maintain backwards compatibility for general peer disconnection
2025-07-05 19:35:37 +02:00