Files
bitchat/bitchat/Views/AppInfoView.swift
T
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

356 lines
16 KiB
Swift

import SwiftUI
struct AppInfoView: View {
@Environment(\.dismiss) var dismiss
@Environment(\.colorScheme) var colorScheme
private var backgroundColor: Color {
colorScheme == .dark ? Color.black : Color.white
}
private var textColor: Color {
colorScheme == .dark ? Color.green : Color(red: 0, green: 0.5, blue: 0)
}
private var secondaryTextColor: Color {
colorScheme == .dark ? Color.green.opacity(0.8) : Color(red: 0, green: 0.5, blue: 0).opacity(0.8)
}
var body: some View {
#if os(macOS)
VStack(spacing: 0) {
// Custom header for macOS
HStack {
Spacer()
Button("DONE") {
dismiss()
}
.buttonStyle(.plain)
.foregroundColor(textColor)
.padding()
}
.background(backgroundColor.opacity(0.95))
ScrollView {
VStack(alignment: .leading, spacing: 24) {
// Header
VStack(alignment: .center, spacing: 8) {
Text("bitchat*")
.font(.system(size: 32, weight: .bold, design: .monospaced))
.foregroundColor(textColor)
Text("mesh sidegroupchat")
.font(.system(size: 16, design: .monospaced))
.foregroundColor(secondaryTextColor)
}
.frame(maxWidth: .infinity)
.padding(.vertical)
// Features
VStack(alignment: .leading, spacing: 16) {
SectionHeader("FEATURES")
FeatureRow(icon: "wifi.slash", title: "offline communication",
description: "works without internet using Bluetooth mesh networking")
FeatureRow(icon: "lock.shield", title: "end-to-end encryption",
description: "private messages encrypted with noise protocol")
FeatureRow(icon: "antenna.radiowaves.left.and.right", title: "extended range",
description: "messages relay through peers, increasing the distance")
FeatureRow(icon: "star.fill", title: "favorites",
description: "store-and-forward messages for favorite people")
FeatureRow(icon: "at", title: "mentions",
description: "use @nickname to notify specific people")
FeatureRow(icon: "number", title: "channels",
description: "create #channels for topic-based conversations")
FeatureRow(icon: "lock.fill", title: "private channels",
description: "secure channels with passwords and noise encryption")
}
// Privacy
VStack(alignment: .leading, spacing: 16) {
SectionHeader("Privacy")
FeatureRow(icon: "eye.slash", title: "no tracking",
description: "no servers, accounts, or data collection")
FeatureRow(icon: "shuffle", title: "ephemeral identity",
description: "new peer ID generated each session")
FeatureRow(icon: "hand.raised.fill", title: "panic mode",
description: "triple-tap logo to instantly clear all data")
}
// How to Use
VStack(alignment: .leading, spacing: 16) {
SectionHeader("How to Use")
VStack(alignment: .leading, spacing: 8) {
Text("• set your nickname by tapping it")
Text("• swipe left for sidebar")
Text("• tap a peer to start a private chat")
Text("• use @nickname to mention someone")
Text("• use #channelname to create/join channels")
Text("• triple-tap the logo for panic mode")
}
.font(.system(size: 14, design: .monospaced))
.foregroundColor(textColor)
}
// Commands
VStack(alignment: .leading, spacing: 16) {
SectionHeader("Commands")
VStack(alignment: .leading, spacing: 8) {
Text("/j #channel - join or create a channel")
Text("/m @name - send private message")
Text("/w - see who's online")
Text("/channels - show all discovered channels")
Text("/block @name - block a peer")
Text("/block - list blocked peers")
Text("/unblock @name - unblock a peer")
Text("/clear - clear current chat")
Text("/hug @name - send someone a hug")
Text("/slap @name - slap with a trout")
}
.font(.system(size: 14, design: .monospaced))
.foregroundColor(textColor)
}
// Technical Details
VStack(alignment: .leading, spacing: 16) {
SectionHeader("Technical Details")
VStack(alignment: .leading, spacing: 8) {
Text("protocol: custom binary over BLE")
Text("encryption: noise protocol")
Text("range: ~30m direct, 300m+ with relay")
Text("store & forward: 12h for all, ∞ for favorites")
Text("battery: Adaptive scanning based on level")
Text("platform: Universal (iOS, iPadOS, macOS)")
Text("channels: Password-protected with key commitments")
Text("storage: Keychain for passwords, encrypted retention")
}
.font(.system(size: 14, design: .monospaced))
.foregroundColor(textColor)
}
// Version
HStack {
Spacer()
Text("VERSION 1.0.0")
.font(.system(size: 12, design: .monospaced))
.foregroundColor(secondaryTextColor)
Spacer()
}
.padding(.top)
}
.padding()
}
.background(backgroundColor)
}
.frame(width: 600, height: 700)
#else
NavigationView {
ScrollView {
VStack(alignment: .leading, spacing: 24) {
// Header
VStack(alignment: .center, spacing: 8) {
Text("bitchat*")
.font(.system(size: 32, weight: .bold, design: .monospaced))
.foregroundColor(textColor)
Text("mesh sidegroupchat")
.font(.system(size: 16, design: .monospaced))
.foregroundColor(secondaryTextColor)
}
.frame(maxWidth: .infinity)
.padding(.vertical)
// Features
VStack(alignment: .leading, spacing: 16) {
SectionHeader("Features")
FeatureRow(icon: "wifi.slash", title: "offline communication",
description: "works without internet using Bluetooth mesh networking")
FeatureRow(icon: "lock.shield", title: "end-to-end encryption",
description: "private messages and channels encrypted with noise protocol")
FeatureRow(icon: "antenna.radiowaves.left.and.right", title: "Extended Range",
description: "messages relay through peers, increasing the distance")
FeatureRow(icon: "star.fill", title: "favorites",
description: "store-and-forward messages for favorite people")
FeatureRow(icon: "at", title: "mentions",
description: "use @nickname to notify specific people")
FeatureRow(icon: "number", title: "channels",
description: "create #channels for topic-based conversations")
FeatureRow(icon: "lock.fill", title: "private channels",
description: "secure channels with passwords and noise encryption")
}
// Privacy
VStack(alignment: .leading, spacing: 16) {
SectionHeader("Privacy")
FeatureRow(icon: "eye.slash", title: "no tracking",
description: "no servers, accounts, or data collection")
FeatureRow(icon: "shuffle", title: "ephemeral identity",
description: "new peer ID generated each session")
FeatureRow(icon: "hand.raised.fill", title: "panic mode",
description: "triple-tap logo to instantly clear all data")
}
// How to Use
VStack(alignment: .leading, spacing: 16) {
SectionHeader("How to Use")
VStack(alignment: .leading, spacing: 8) {
Text("• set your nickname by tapping it")
Text("• swipe left for sidebar")
Text("• tap a peer to start a private chat")
Text("• use @nickname to mention someone")
Text("• use #channelname to create/join channels")
Text("• triple-tap the logo for panic mode")
}
.font(.system(size: 14, design: .monospaced))
.foregroundColor(textColor)
}
// Commands
VStack(alignment: .leading, spacing: 16) {
SectionHeader("Commands")
VStack(alignment: .leading, spacing: 8) {
Text("/j #channel - join or create a channel")
Text("/m @name - send private message")
Text("/w - see who's online")
Text("/channels - show all discovered channels")
Text("/block @name - block a peer")
Text("/block - list blocked peers")
Text("/unblock @name - unblock a peer")
Text("/clear - clear current chat")
Text("/hug @name - send someone a hug")
Text("/slap @name - slap with a trout")
}
.font(.system(size: 14, design: .monospaced))
.foregroundColor(textColor)
}
// Technical Details
VStack(alignment: .leading, spacing: 16) {
SectionHeader("Technical Details")
VStack(alignment: .leading, spacing: 8) {
Text("protocol: custom binary over BLE")
Text("encryption: noise protocol")
Text("range: ~30m direct, 300m+ with relay")
Text("store & forward: 12h for all, ∞ for favorites")
Text("battery: adaptive scanning based on level")
Text("platform: universal (iOS, iPadOS, macOS)")
Text("channels: password-protected with key commitments")
Text("storage: keychain for passwords, encrypted retention")
}
.font(.system(size: 14, design: .monospaced))
.foregroundColor(textColor)
}
// Version
HStack {
Spacer()
Text("VERSION 1.0.0")
.font(.system(size: 12, design: .monospaced))
.foregroundColor(secondaryTextColor)
Spacer()
}
.padding(.top)
}
.padding()
}
.background(backgroundColor)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("DONE") {
dismiss()
}
.foregroundColor(textColor)
}
}
}
#endif
}
}
struct SectionHeader: View {
let title: String
@Environment(\.colorScheme) var colorScheme
private var textColor: Color {
colorScheme == .dark ? Color.green : Color(red: 0, green: 0.5, blue: 0)
}
init(_ title: String) {
self.title = title
}
var body: some View {
Text(title.uppercased())
.font(.system(size: 16, weight: .bold, design: .monospaced))
.foregroundColor(textColor)
.padding(.top, 8)
}
}
struct FeatureRow: View {
let icon: String
let title: String
let description: String
@Environment(\.colorScheme) var colorScheme
private var textColor: Color {
colorScheme == .dark ? Color.green : Color(red: 0, green: 0.5, blue: 0)
}
private var secondaryTextColor: Color {
colorScheme == .dark ? Color.green.opacity(0.8) : Color(red: 0, green: 0.5, blue: 0).opacity(0.8)
}
var body: some View {
HStack(alignment: .top, spacing: 12) {
Image(systemName: icon)
.font(.system(size: 20))
.foregroundColor(textColor)
.frame(width: 30)
VStack(alignment: .leading, spacing: 4) {
Text(title)
.font(.system(size: 14, weight: .semibold, design: .monospaced))
.foregroundColor(textColor)
Text(description)
.font(.system(size: 12, design: .monospaced))
.foregroundColor(secondaryTextColor)
.fixedSize(horizontal: false, vertical: true)
}
Spacer()
}
}
}
#Preview {
AppInfoView()
}