BLE announce trust verified the packet signature against the Ed25519
signing key carried inside the same announce, and the trust policy only
rejected on noise-key mismatch. Since peerIDs derive from the broadcast
(public) noise key, an on-mesh attacker could replay a victim's
peerID+noiseKey with their own signing key, nickname, and a valid
self-signature; the registry/persisted identity was then overwritten
unconditionally, enabling mesh nickname spoofing and forged attribution
of signed public/broadcast messages.
Fix: TOFU-pin the Ed25519 signing key per peer (noise-key-derived
peerID) on the announce path.
- BLEAnnounceTrustPolicy rejects announces whose signing key differs
from the one already recorded for the peer (.signingKeyMismatch).
- BLEPeerRegistry.upsertVerifiedAnnounce refuses to replace a pinned
signing key (returns nil) and never drops a pinned key.
- BLEAnnounceHandler falls back to the persisted cryptographic identity
(persistedSigningPublicKey) when the registry has no signing key, so
the pin survives registry eviction and app restart.
- SecureIdentityStateManager.upsertCryptographicIdentity refuses to
replace a persisted signing key with a different one, and the
cryptographic identities (incl. the pin) now live in the encrypted,
persisted IdentityCache with synchronous, teardown-safe saves.
Rebased onto main and integrated with #1432 (Noise session identity
binding + signed leaves): both are complementary. #1432's signed-leave
verification reads the same registry/persisted signing key that this
change protects from announce-path poisoning. main's evolution is kept:
BLEPeerRegistry.upsertVerifiedAnnounce still takes capabilities/
bridgeGeohash (nil return propagates as a refusal), the handler's
linkBoundToOtherPeer env is preserved, CryptographicIdentity keeps
main's field set, and EphemeralIdentity uses main's initializer.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* Update .gitignore to not ignored shared settings
`xcshareddata/` should be added to the repo to sync the scheme settings (like running parallel tests or turning on code coverage…)
* Add `bitchat (iOS)` shared scheme
* Parallelized and randomized test execution
* Gather code coverage for `bitchat_iOS` target
* Create configs files with basic settings populated
* Add Configs and set the global Debug/Release settings
* Update build settings to be read from the configs
* Remove `xcodegen`’s `project.yml`
* Configurable and dynamic bundle and group ids
* Simplified local development with custom Team IDs
* 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>
* 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>
* UI: prefer mesh radio icon when connected; map short peer ID to full Noise key; rename ephemeral mapping to shortIDToNoiseKey; ensure header flips to purple globe on disconnect and keeps name.
* chore: stop tracking build artifacts; ignore .DerivedData and .Result*
* logging: add global threshold via BITCHAT_LOG_LEVEL and demote chatty logs to debug; keep critical errors/warnings and key state transitions
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
- Fixed mock service property overrides to match base class properties
- Added missing CryptoKit imports where needed
- Fixed immutable property assignments by creating new instances
- Replaced XCTAssertThrows with XCTAssertThrowsError
- Fixed DeliveryAck serialization method names (serialize -> encode)
- Fixed unused variable warnings
- Ensured all BitchatPacket modifications create new instances
- Fixed BitchatMessage property mutations by creating new instances
All test targets now build successfully for both iOS and macOS platforms.