mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 18:05:19 +00:00
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>
This commit is contained in:
@@ -719,9 +719,18 @@ struct ContentView: View {
|
||||
Spacer()
|
||||
}
|
||||
} else {
|
||||
Text(peer.displayName)
|
||||
.font(.system(size: 14, design: .monospaced))
|
||||
.foregroundColor(peer.isFavorite || peerNicknames[peer.id] != nil ? textColor : secondaryTextColor)
|
||||
// Render nickname with light-gray '#abcd' suffix if present
|
||||
let parts = splitNameSuffix(peer.displayName)
|
||||
HStack(spacing: 0) {
|
||||
Text(parts.base)
|
||||
.font(.system(size: 14, design: .monospaced))
|
||||
.foregroundColor(peer.isFavorite || peerNicknames[peer.id] != nil ? textColor : secondaryTextColor)
|
||||
if !parts.suffix.isEmpty {
|
||||
Text(parts.suffix)
|
||||
.font(.system(size: 14, design: .monospaced))
|
||||
.foregroundColor(Color.secondary.opacity(0.6))
|
||||
}
|
||||
}
|
||||
|
||||
// Encryption status icon (after peer name)
|
||||
if let icon = peer.encryptionStatus.icon {
|
||||
@@ -844,6 +853,19 @@ struct ContentView: View {
|
||||
.foregroundColor(textColor)
|
||||
}
|
||||
}
|
||||
|
||||
// Split a name into base and a '#abcd' suffix if present
|
||||
private func splitNameSuffix(_ name: String) -> (base: String, suffix: String) {
|
||||
guard name.count >= 5 else { return (name, "") }
|
||||
let suffix = String(name.suffix(5))
|
||||
if suffix.first == "#", suffix.dropFirst().allSatisfy({ c in
|
||||
("0"..."9").contains(String(c)) || ("a"..."f").contains(String(c)) || ("A"..."F").contains(String(c))
|
||||
}) {
|
||||
let base = String(name.dropLast(5))
|
||||
return (base, suffix)
|
||||
}
|
||||
return (name, "")
|
||||
}
|
||||
|
||||
|
||||
private var mainHeaderView: some View {
|
||||
@@ -925,7 +947,7 @@ struct ContentView: View {
|
||||
.font(.system(size: 12, design: .monospaced))
|
||||
.accessibilityHidden(true)
|
||||
}
|
||||
.foregroundColor(isNostrOnly ? Color.purple : (meshPeerCount > 0 ? textColor : Color.red))
|
||||
.foregroundColor(isNostrOnly ? Color.purple : (meshPeerCount > 0 ? Color.blue : Color.secondary))
|
||||
}
|
||||
.onTapGesture {
|
||||
withAnimation(.easeInOut(duration: 0.2)) {
|
||||
|
||||
Reference in New Issue
Block a user