ios_client
This commit is contained in:
346
ios_client 0.8.5/ARCHITECTURE.md
Normal file
346
ios_client 0.8.5/ARCHITECTURE.md
Normal file
@@ -0,0 +1,346 @@
|
||||
# Kecalek iOS — Architecture & Features
|
||||
|
||||
**Version:** 0.8.5
|
||||
**Platform:** iOS 26+ / Swift 6
|
||||
**Files:** 57 Swift source files
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
Kecalek/
|
||||
├── KecalekApp.swift # App entry point, tab navigation
|
||||
├── AppState.swift # Login state, connection monitoring, reconnection
|
||||
├── Core/
|
||||
│ ├── ChatClient.swift # Main actor — all server communication & crypto (3400+ lines)
|
||||
│ ├── KeyStorage.swift # Persistent key storage (RSA, Ed25519, sessions, TOFU)
|
||||
│ ├── KeychainService.swift # Secure credential storage (biometric auth)
|
||||
│ └── MessageCache.swift # Encrypted message cache (per-conversation)
|
||||
├── Crypto/
|
||||
│ ├── CryptoUtils.swift # AES-256-GCM, HKDF, chain KDF, local encryption
|
||||
│ ├── DoubleRatchet.swift # Signal Double Ratchet (DM encryption)
|
||||
│ ├── X3DH.swift # Extended Triple Diffie-Hellman (session init)
|
||||
│ ├── SenderKeyState.swift # Sender Key chains (group encryption)
|
||||
│ ├── Ed25519Crypto.swift # Identity key generation & signing
|
||||
│ ├── X25519Crypto.swift # DH key agreement & Ed25519↔X25519 conversion
|
||||
│ ├── RSACrypto.swift # RSA-2048 key generation, PKCS#1/PKCS#8
|
||||
│ ├── KeyEncryption.swift # ECP1 format: PBKDF2 600K + AES-GCM key encryption
|
||||
│ ├── FieldArithmetic.swift # GF(2^255-19) for Ed25519→X25519 conversion
|
||||
│ ├── MessagePadding.swift # Bucket-based padding (64B–64KB) for metadata privacy
|
||||
│ ├── ContactVerification.swift # Fingerprints, safety numbers, QR codes
|
||||
│ └── CryptoErrors.swift # Error types
|
||||
├── Network/
|
||||
│ ├── ConnectionManager.swift # TCP/TLS via Network.framework (actor)
|
||||
│ └── ProtocolHandler.swift # Newline-delimited JSON encoding/decoding
|
||||
├── Models/
|
||||
│ ├── Message.swift # Message, reactions, replies, pins, files, images
|
||||
│ ├── Conversation.swift # Conversation, members, group detection
|
||||
│ ├── User.swift # User, UserProfile
|
||||
│ ├── DeviceBundle.swift # X3DH key bundle per device
|
||||
│ └── Invitation.swift # Group invitation
|
||||
├── ViewModels/
|
||||
│ ├── AuthViewModel.swift # Login, register, pairing, biometrics
|
||||
│ ├── ChatViewModel.swift # Messages, sending, search, reactions, pins
|
||||
│ ├── ConversationListVM.swift # Conversations, online users, favorites, avatars
|
||||
│ ├── ProfileViewModel.swift # Profile editing, avatar upload
|
||||
│ └── VerificationVM.swift # Safety numbers, QR verification
|
||||
├── Views/
|
||||
│ ├── Auth/ # LoginView, RegisterView, PairingView, AuthorizeDeviceView
|
||||
│ ├── Chat/ # ChatView, MessageBubbleView, MessageInputView, etc.
|
||||
│ ├── Components/ # CircularAvatarView, ConnectionIndicator, OnlineDotOverlay
|
||||
│ ├── Conversations/ # ConversationListView, ConversationRowView, NewConversationSheet
|
||||
│ ├── Groups/ # GroupInfoView, InvitationBanner, CreateGroupSheet
|
||||
│ ├── Profile/ # ProfileView, EditProfileView
|
||||
│ └── Verification/ # SafetyNumberView, QRCodeScannerView, VerificationStatusView
|
||||
└── Utilities/
|
||||
├── Constants.swift # Version, limits, timeouts, server defaults, crypto params
|
||||
└── Extensions.swift # Data hex/base64, DateParsing, Dictionary helpers
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
### Pattern: MVVM + Actor Isolation
|
||||
|
||||
- **Views** — SwiftUI, declarative UI, bind to `@Observable` ViewModels
|
||||
- **ViewModels** — `@Observable final class`, business logic, async operations
|
||||
- **ChatClient** — `actor`, single source of truth for all crypto & network ops
|
||||
- **Models** — plain `struct`s with `Identifiable`, `Codable`
|
||||
|
||||
### Concurrency Model
|
||||
|
||||
- `ChatClient` is an **actor** — all crypto state (keys, sessions, ratchets) is thread-safe
|
||||
- All network calls use `async/await`
|
||||
- Real-time notifications via `AsyncStream<ChatNotification>` (multiple subscribers)
|
||||
- Background tasks: avatar loading, reconnection, notification listening
|
||||
|
||||
### Connection Lifecycle
|
||||
|
||||
```
|
||||
App Launch → Login (RSA challenge-response) → TCP/TLS connected
|
||||
→ Background listener loop reads messages continuously
|
||||
→ Notifications broadcast via AsyncStream to all subscribers
|
||||
→ On disconnect: exponential backoff reconnect (1s → 30s, 5 attempts)
|
||||
→ On auth failure: immediate logout (keys rotated)
|
||||
→ On foreground: check connection health, reconnect if stale (>30s)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Encryption (Signal Protocol)
|
||||
|
||||
### Key Types
|
||||
|
||||
| Key | Algorithm | Size | Purpose |
|
||||
|-----|-----------|------|---------|
|
||||
| RSA | RSA-2048 | 256B | Login authentication (challenge-response) |
|
||||
| Identity Key (IK) | Ed25519 | 32B | Long-term identity, signs SPK |
|
||||
| Signed Pre-Key (SPK) | X25519 | 32B | Medium-term, rotated every 7 days |
|
||||
| One-Time Pre-Keys (OPKs) | X25519 | 32B each | Single-use, batch of 50, replenish at 20 |
|
||||
| Ratchet Keys | X25519 | 32B | Ephemeral per DH ratchet step |
|
||||
| Sender Keys | Random | 32B | Per-group, per-sender chain key |
|
||||
|
||||
### DM Encryption (X3DH + Double Ratchet)
|
||||
|
||||
1. **Session Init (X3DH):**
|
||||
- Alice computes: DH(IK_A, SPK_B) || DH(EK_A, IK_B) || DH(EK_A, SPK_B) || DH(EK_A, OPK_B)
|
||||
- HKDF-SHA256 derives 32-byte shared secret
|
||||
- Double Ratchet initialized
|
||||
|
||||
2. **Message Encryption (Double Ratchet):**
|
||||
- Root key → chain key → message key (HKDF chain)
|
||||
- DH ratchet step on each direction change
|
||||
- AES-256-GCM with derived message key
|
||||
- AAD: ratchet header (dh_pub, n, pn)
|
||||
- Max skip: 256 messages
|
||||
|
||||
3. **Message Format:**
|
||||
```
|
||||
plaintext → MessagePadding.pad() → AES-256-GCM encrypt → base64 → JSON
|
||||
```
|
||||
|
||||
### Group Encryption (Sender Keys)
|
||||
|
||||
1. Each member maintains own sender key chain
|
||||
2. Sender key distributed to all members via pairwise Double Ratchet DMs
|
||||
3. Messages encrypted with AES-256-GCM using derived chain key
|
||||
4. Chain ID = SHA-256(sender_key) for verification
|
||||
5. Max skip: 256 messages per chain
|
||||
|
||||
### Message Padding
|
||||
|
||||
Bucket sizes: `64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536` bytes
|
||||
|
||||
```
|
||||
Format: 0x01 | plaintext | random_padding | pad_length (4B big-endian)
|
||||
```
|
||||
|
||||
All messages padded to nearest bucket size — prevents metadata analysis of message lengths.
|
||||
|
||||
### Self-Encryption
|
||||
|
||||
- Derived from identity private key via HKDF
|
||||
- Encrypts own message copies for multi-device access
|
||||
- Static key — same across all user's devices
|
||||
|
||||
### Contact Verification (TOFU)
|
||||
|
||||
- **Fingerprint:** Iterated SHA-512 (5200 rounds) over identity key
|
||||
- **Safety Number:** 60 digits (12 groups of 5), deterministic ordering by userId
|
||||
- **QR Code:** Binary `version(1B) + uid_len(1B) + uid + identity_key(32B)`
|
||||
- **TOFU Registry:** Track first-seen identity keys, alert on change
|
||||
- **Verification Status:** unverified → trusted (TOFU) → verified (manual/QR)
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
### Authentication & Accounts
|
||||
|
||||
- [x] **Registration** — email + password + verification code
|
||||
- [x] **Login** — RSA challenge-response authentication
|
||||
- [x] **Biometric Login** — Face ID / Touch ID via Keychain
|
||||
- [x] **PoW Challenge** — SHA-256 proof-of-work during registration surge
|
||||
- [x] **Brute-Force Lockout** — exponential backoff (2^n seconds, max 300s)
|
||||
- [x] **Change Username** — update display name
|
||||
- [x] **Change Password** — re-encrypt RSA + Ed25519 keys with new PBKDF2 password
|
||||
- [x] **Key Rotation** — regenerate all keys with grace period for in-flight sessions
|
||||
- [x] **Logout** — clean disconnect, clear session
|
||||
|
||||
### Multi-Device
|
||||
|
||||
- [x] **Device Pairing** — authorize new device via pairing flow
|
||||
- [x] **Device List** — view all authorized devices
|
||||
- [x] **Device Removal** — revoke device authorization
|
||||
- [x] **Self-Encryption** — own messages readable on all devices
|
||||
|
||||
### Messaging
|
||||
|
||||
- [x] **Text Messages** — encrypted DM and group messages
|
||||
- [x] **Message Replies** — reply-to with visual indicator
|
||||
- [x] **Reactions** — 6 emoji reactions (👍❤️😂😮😢👎) with toggle
|
||||
- [x] **Message Pinning** — pin/unpin with pinned messages sheet
|
||||
- [x] **Message Deletion** — soft delete with "Message deleted" indicator
|
||||
- [x] **Message Forwarding** — forward to any conversation with source attribution
|
||||
- [x] **Message Search** — full-text search with result navigation (prev/next)
|
||||
- [x] **Read Receipts** — track who read each message
|
||||
- [x] **Delivery Receipts** — sent → delivered → read indicators (checkmarks)
|
||||
- [x] **Incremental Sync** — fetch only new messages via `after_ts`
|
||||
- [x] **Deleted Sync** — `get_deleted_since` for incremental deletion sync
|
||||
- [x] **Message Padding** — metadata privacy via bucket-based padding
|
||||
|
||||
### Media & Files
|
||||
|
||||
- [x] **Image Upload** — encrypt + chunked upload (24KB chunks)
|
||||
- [x] **Image Thumbnails** — base64 JPEG preview inline
|
||||
- [x] **Image Viewer** — full-screen with pinch zoom
|
||||
- [x] **File Upload** — any file type with mime detection
|
||||
- [x] **File Download** — decrypt + share via system share sheet
|
||||
- [x] **File Icons** — type-based system icons (PDF, DOC, ZIP, etc.)
|
||||
|
||||
### Conversations
|
||||
|
||||
- [x] **Direct Messages** — 1-on-1 encrypted chat
|
||||
- [x] **Group Conversations** — multi-member with Sender Keys
|
||||
- [x] **Create Conversation** — new DM or group
|
||||
- [x] **Rename Conversation** — group rename (creator only)
|
||||
- [x] **Delete Conversation** — remove DM or delete group
|
||||
- [x] **Favorites** — pin conversations to top with star icon
|
||||
- [x] **Unread Counts** — per-conversation badge
|
||||
- [x] **Online Status** — real-time presence (green dot)
|
||||
|
||||
### Group Management
|
||||
|
||||
- [x] **Add Member** — by email
|
||||
- [x] **Remove Member** — creator only
|
||||
- [x] **Leave Group** — with confirmation
|
||||
- [x] **Group Avatar** — upload/change group photo
|
||||
- [x] **Group Rename** — change group name
|
||||
- [x] **Group Invitations** — accept/decline with banner UI
|
||||
|
||||
### Profile
|
||||
|
||||
- [x] **User Profile** — username, email, phone, location
|
||||
- [x] **Avatar** — upload/change profile photo
|
||||
- [x] **Field Visibility** — toggle phone/location visibility
|
||||
- [x] **View Other Profiles** — see other users' info (respects visibility)
|
||||
|
||||
### Contact Verification
|
||||
|
||||
- [x] **Safety Numbers** — 60-digit verification code per contact pair
|
||||
- [x] **Fingerprints** — identity key fingerprints
|
||||
- [x] **QR Code Generation** — generate scannable verification QR
|
||||
- [x] **QR Code Scanning** — camera-based QR scan for verification
|
||||
- [x] **Verification Status** — verified (green) / trusted (blue) / unverified (gray)
|
||||
- [x] **TOFU Registry** — track identity key first-seen, detect changes
|
||||
- [x] **Shield Icon** — verification badge in chat toolbar
|
||||
|
||||
### Connection & Reliability
|
||||
|
||||
- [x] **TCP/TLS** — Network.framework with optional TLS
|
||||
- [x] **Configurable Server** — host, port, TLS toggle in login screen
|
||||
- [x] **Connection Indicator** — visual status (disconnected/connecting/connected)
|
||||
- [x] **Auto-Reconnect** — exponential backoff (1s → 30s, 5 attempts)
|
||||
- [x] **Background/Foreground Handling** — reconnect when returning from background
|
||||
- [x] **Auth Failure Detection** — immediate logout on key rotation
|
||||
|
||||
### Caching & Storage
|
||||
|
||||
- [x] **Message Cache** — encrypted per-conversation cache on disk
|
||||
- [x] **Avatar Cache** — disk + in-memory cache
|
||||
- [x] **Conversation Cache** — cached list for instant UI
|
||||
- [x] **Session Persistence** — Double Ratchet states saved encrypted
|
||||
- [x] **Sender Key Persistence** — group key chains saved encrypted
|
||||
- [x] **Device Bundle Cache** — 5-minute TTL in-memory
|
||||
- [x] **Keychain Storage** — biometric-protected credentials
|
||||
|
||||
---
|
||||
|
||||
## Network Protocol
|
||||
|
||||
### Transport
|
||||
|
||||
```
|
||||
TCP → optional TLS → Newline-delimited JSON (\n terminated)
|
||||
```
|
||||
|
||||
### Message Format
|
||||
|
||||
```json
|
||||
{"type": "send_message", "request_id": "uuid", "conversation_id": "...", "ciphertext": "base64..."}
|
||||
```
|
||||
|
||||
### API Methods (36 endpoints)
|
||||
|
||||
**Auth:** `register`, `register_confirm`, `login_start`, `login_finish`, `change_username`, `change_password`
|
||||
|
||||
**Keys:** `get_key_bundle`, `ensure_prekeys`, `get_prekey_count`, `rotate_keys`, `reset_session`
|
||||
|
||||
**Messaging:** `send_message`, `get_messages`, `delete_message`, `mark_read`, `mark_conversation_read`, `react_message`, `pin_message`, `get_pinned_messages`, `get_deleted_since`, `forward_message`, `confirm_delivery`, `search_messages`
|
||||
|
||||
**Conversations:** `list_conversations`, `create_conversation`, `find_conversation`, `delete_conversation`, `rename_conversation`, `add_member`, `remove_member`, `leave_group`, `accept_invitation`, `decline_invitation`, `list_invitations`
|
||||
|
||||
**Profiles:** `get_profile`, `update_profile`, `update_avatar`, `get_avatar`, `update_group_avatar`, `get_group_avatar`
|
||||
|
||||
**Files:** `upload_file`, `download_file`
|
||||
|
||||
**Devices:** `list_devices`, `remove_device`, `pairing_start`, `pairing_wait`, `authorize_device`
|
||||
|
||||
### Notification Types (17 real-time events)
|
||||
|
||||
```
|
||||
new_message, messages_read, message_deleted, message_reacted,
|
||||
message_pinned, message_unpinned, message_delivered,
|
||||
conversation_created, conversation_renamed, conversation_deleted,
|
||||
member_added, member_removed, group_invitation,
|
||||
user_online, user_offline, online_users,
|
||||
session_reset, keys_updated
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Storage Layout
|
||||
|
||||
```
|
||||
~/Library/Application Support/EncryptedChat/{email}/
|
||||
├── private.pem # RSA private key (password-protected)
|
||||
├── public.pem # RSA public key
|
||||
├── identity_private.bin # Ed25519 private (ECP1: PBKDF2 + AES-GCM)
|
||||
├── identity_public.bin # Ed25519 public
|
||||
├── spk_private.bin # Current signed pre-key (X25519)
|
||||
├── spk_id.txt # SPK ID
|
||||
├── prevspk_private.bin # Previous SPK (grace period)
|
||||
├── prevspk_id.txt
|
||||
├── opk_{id}.bin # One-time pre-keys
|
||||
├── sessions/
|
||||
│ └── {userId}_{deviceId}.bin # Double Ratchet state (encrypted)
|
||||
├── sender_keys/
|
||||
│ └── {convId}_{senderId}_{deviceId}.bin # Sender Key chain (encrypted)
|
||||
├── message_cache/
|
||||
│ └── {convId}.json # Message cache (encrypted)
|
||||
├── conversations_cache.json # Conversation list cache (encrypted)
|
||||
├── avatars/
|
||||
│ └── {convId}.bin # Avatar image data (encrypted)
|
||||
├── known_identity_keys.bin # TOFU registry (encrypted)
|
||||
├── verified_contacts.bin # Verified contacts (encrypted)
|
||||
└── favorites.bin # Favorite conversation IDs (encrypted)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Build
|
||||
|
||||
```bash
|
||||
# Xcode build
|
||||
open /Users/filip/Desktop/kecalek_ios/Kecalek/Kecalek.xcodeproj
|
||||
|
||||
# Command-line build
|
||||
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer \
|
||||
xcodebuild -scheme Kecalek \
|
||||
-destination 'platform=iOS Simulator,name=iPhone 17 Pro' \
|
||||
build
|
||||
```
|
||||
|
||||
**Result:** 57 files, 0 errors, 0 warnings.
|
||||
Reference in New Issue
Block a user