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
This commit is contained in:
jack
2026-07-06 22:13:31 +02:00
32 changed files with 2887 additions and 36 deletions
@@ -25,9 +25,11 @@ public enum MessageType: UInt8 {
case fragment = 0x20 // Single fragment type for large messages
case fileTransfer = 0x22 // Binary file/audio/image payloads
// 0x23, 0x25-0x28 reserved for in-flight protocol work.
// 0x23/0x26-0x28 reserved by other in-flight features.
case prekeyBundle = 0x24 // Signed batch of one-time prekeys (gossiped)
case groupMessage = 0x25 // Group-encrypted broadcast (cleartext group ID, ChaChaPoly body)
public var description: String {
switch self {
case .announce: return "announce"
@@ -40,6 +42,7 @@ public enum MessageType: UInt8 {
case .fragment: return "fragment"
case .fileTransfer: return "fileTransfer"
case .prekeyBundle: return "prekeyBundle"
case .groupMessage: return "groupMessage"
}
}
}
@@ -34,6 +34,9 @@ public struct PeerID: Equatable, Hashable, Sendable {
case geoDM = "nostr_"
/// `"nostr:"` (+ 8 characters hex)
case geoChat = "nostr:"
/// `"group_"` (+ 32 characters hex) virtual conversation ID for a
/// private group (16-byte group ID). Never routed to a single peer.
case group = "group_"
}
public let prefix: Prefix
@@ -96,6 +99,22 @@ public extension PeerID {
}
}
// MARK: - Group Conversation Helpers
public extension PeerID {
/// Convenience init to create a virtual group conversation PeerID from a
/// 16-byte group ID ("group_" + 32 hex characters).
init(groupID: Data) {
self.init(str: Prefix.group.rawValue + groupID.hexEncodedString())
}
/// The 16-byte group ID behind a "group_" PeerID, if this is one.
var groupIDData: Data? {
guard isGroup, bare.count == 32 else { return nil }
return Data(hexString: bare)
}
}
// MARK: - Noise Public Key Helpers
public extension PeerID {
@@ -143,6 +162,11 @@ public extension PeerID {
prefix == .geoDM
}
/// Returns true if `id` starts with "`group_`"
var isGroup: Bool {
prefix == .group
}
func toPercentEncoded() -> String {
id.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? id
}