docs: add ESP32 and iOS agent architecture reference

- reference/esp32-agent/: DESIGN, HARDWARE, API_COMPAT, ARCHITECTURE, README

- reference/ios-agent/: DESIGN, API_COMPAT, UI_DESIGN, ARCHITECTURE, README

- Both mirror Android agent architecture, UI design, and heartbeat flow

- Architecture-only (no code) — avoids submodule conflicts

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
datadunia
2026-07-06 14:20:10 +07:00
parent 4af46dadad
commit 84689b208e
10 changed files with 3565 additions and 0 deletions
+425
View File
@@ -0,0 +1,425 @@
# iOS Agent — Technical Design Document
**Version**: 1.0.0
**Date**: 2026-07-06
**Status**: Draft
**Mirror**: Android Agent (`apps/android-agent/`)
## 1. Executive Summary
NexusGuard iOS Agent is an iOS-based WireGuard client for mobile devices. It mirrors the Android agent's architecture, UI design, and heartbeat flow, using iOS-native APIs (NetworkExtension, CryptoKit, Keychain).
## 2. Goals & Non-Goals
### Goals
- iOS-based WireGuard tunnel (NetworkExtension)
- Auto-provisioning via HTTP (same API as Android/ESP32)
- Heartbeat monitoring with config sync (30s interval)
- Keychain-based config storage (hardware-backed encryption)
- SwiftUI UI matching Android agent design
- Background operation via NetworkExtension
### Non-Goals
- gRPC support (not needed for mobile)
- Port forwarding (userspace agent only)
- Jailbroken device support
- macOS/iPadOS support (iPhone only for v1)
## 3. Architecture
### 3.1 System Architecture
```
┌─────────────────────────────────────────────────────────┐
│ iOS (SwiftUI) │
├─────────────────────────────────────────────────────────┤
│ App Layer │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ContentView│ │SettingsView│ │LogView │ │PortView │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │ │
│ ┌────┴─────────────┴────────────┴─────────────┴────┐ │
│ │ AgentManager │ │
│ │ (orchestrates all components) │ │
│ └──────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────┤
│ Service Layer │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │Provisioning│ │Heartbeat│ │TunnelMgr │ │ConfigMgr│ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │ │
│ ┌────┴─────────────┴────────────┴─────────────┴────┐ │
│ │ CryptoManager │ │
│ │ AES-256-GCM (CryptoKit) │ │
│ └──────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────┤
│ NetworkExtension Layer │
│ ┌──────────────────────────────────────────────────┐ │
│ │ PacketTunnelProvider │ │
│ │ (WireGuard tunnel via wireguard-apple) │ │
│ └──────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────┤
│ Storage Layer │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Keychain │ │ UserDefaults│ │ CoreData│ │ FileMgr │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────┘
```
### 3.2 Task Architecture
```
iOS Threads/Tasks
├── Main Thread # UI updates
├── AgentManager # Orchestration (async/await)
├── HeartbeatTask # HTTP heartbeat (30s interval)
├── TunnelManager # WireGuard tunnel management
└── BackgroundTask # BGAppRefreshTask (background refresh)
```
### 3.3 State Machine
```
┌─────────────┐
│ BOOT │
└──────┬──────┘
┌─────────────┐
│ APP_INIT │ ◄──────────────────────────────┐
└──────┬──────┘ │
│ loaded │
▼ │
┌─────────────┐ fail ┌─────────────┐│
│ PROVISION │───────────────►│ APP_RETRY ││
└──────┬──────┘ └──────┬──────┘│
│ success │ │
▼ └───────┘
┌─────────────┐
│ TUNNEL_UP │
└──────┬──────┘
┌─────────────┐
│ HEARTBEAT │ ◄─── 30s interval
└──────┬──────┘
│ config_changed
┌─────────────┐
│ TUNNEL_REBUILD │
└──────┬──────┘
└──► HEARTBEAT
```
## 4. Module Design
### 4.1 AgentManager
**Responsibilities**:
- Orchestrate all agent components
- Manage agent lifecycle (start/stop)
- Handle state transitions
**Key Properties**:
```swift
class AgentManager: ObservableObject {
@Published var state: AgentState = .disconnected
@Published var tunnelInfo: TunnelInfo?
@Published var logs: [LogEntry] = []
private let provisioning: ProvisioningService
private let heartbeat: HeartbeatService
private let tunnel: TunnelManager
private let config: KeychainStorage
}
```
**Key Methods**:
```swift
func startAgent() async
func stopAgent()
func rebuildTunnel(with config: WireGuardConfig) async
```
### 4.2 PacketTunnelProvider
**Responsibilities**:
- Handle NetworkExtension tunnel lifecycle
- Start/stop WireGuard tunnel
- Report tunnel status
**Key Methods**:
```swift
override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void)
override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void)
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?)
```
### 4.3 TunnelManager
**Responsibilities**:
- Build WireGuard config from stored keys
- Start/stop tunnel via PacketTunnelProvider
- Monitor tunnel state
- Track last handshake time
**Key Methods**:
```swift
func startTunnel(config: WireGuardConfig) async throws
func stopTunnel()
func isTunnelUp() -> Bool
func getLastHandshake() -> Date?
```
### 4.4 HeartbeatService
**Responsibilities**:
- HTTP POST to `/api/v1/heartbeat` every 30s
- Send device status + tunnel state
- Receive config sync (detect changes)
- Trigger tunnel rebuild if config changed
**Key Methods**:
```swift
func startHeartbeatLoop()
func stopHeartbeat()
func sendHeartbeat(config: WireGuardConfig, tunnelUp: Bool, lastHandshake: Date?) async -> WireGuardConfig?
```
### 4.5 ProvisioningService
**Responsibilities**:
- HTTP POST to `/api/v1/provision`
- Parse encrypted config response
- Decrypt config via CryptoManager
- Store config in Keychain
**Key Methods**:
```swift
func provision(serverUrl: String, token: String, hwid: String) async -> WireGuardConfig?
func decryptConfig(encrypted: String, hwid: String, salt: String) -> WireGuardConfig?
```
### 4.6 CryptoManager
**Responsibilities**:
- Key derivation: SHA-256(hwid + salt)
- AES-256-GCM decryption
- Secure memory handling
**Key Methods**:
```swift
func deriveKey(token: String, hwid: String) -> SymmetricKey
func decrypt(encoded: String, key: SymmetricKey) -> Data?
```
### 4.7 KeychainStorage
**Responsibilities**:
- Store WireGuard keys in Keychain
- Store agent config in UserDefaults
- Secure key access
**Key Methods**:
```swift
func saveConfig(_ config: AgentConfig)
func loadConfig() -> AgentConfig?
func saveWireGuardConfig(_ config: WireGuardConfig)
func loadWireGuardConfig() -> WireGuardConfig?
func clearAll()
```
### 4.8 LogStore
**Responsibilities**:
- Buffer log entries in memory
- Persist to CoreData (optional)
- Provide log stream for UI
**Key Methods**:
```swift
func add(level: LogLevel, tag: String, message: String)
func clear()
func getLogs() -> [LogEntry]
```
## 5. Data Structures
### 5.1 WireGuardConfig
```swift
struct WireGuardConfig: Codable {
let deviceId: String
let privateKey: String
let presharedKey: String
let internalIp: String
let serverPub: String
let endpoint: String
let dns: String
let allowedIps: String
let serverWgIp: String
let configHash: String
let forwardsHash: String
}
```
### 5.2 AgentConfig
```swift
struct AgentConfig: Codable {
let serverUrl: String
let registrationToken: String
let isProvisioned: Bool
}
```
### 5.3 AgentState
```swift
enum AgentState: String {
case disconnected = "disconnected"
case connecting = "connecting"
case connected = "connected"
case failed = "failed"
}
```
### 5.4 LogEntry
```swift
struct LogEntry: Identifiable {
let id = UUID()
let timestamp: Date
let level: LogLevel
let tag: String
let message: String
}
```
## 6. Error Handling
### 6.1 Error Types
```swift
enum AgentError: Error {
case wifiNotConnected
case provisioningFailed(String)
case heartbeatFailed(String)
case cryptoDecryptionFailed
case configInvalid
case tunnelInitFailed
case keychainError(OSStatus)
}
```
### 6.2 Recovery Strategy
| Error | Recovery |
|-------|----------|
| WiFi not connected | Retry 3x, then pause heartbeat |
| HTTP provision fail | Retry 3x, then notify user |
| HTTP heartbeat fail | Log only, continue |
| Crypto decrypt fail | Clear config, re-provision |
| Tunnel init fail | Retry 3x, then notify user |
| Keychain error | Use UserDefaults fallback |
## 7. Background Tasks
### 7.1 BGAppRefreshTask
iOS doesn't have boot receiver like Android. Use Background Tasks:
```swift
// Register task
BGAppRefreshTaskRequest.register(forTaskWithIdentifier: "com.nexusguard.agent.refresh", using: nil) {
task in
self.handleBackgroundRefresh(task: task as! BGAppRefreshTask)
}
// Schedule task
let request = BGAppRefreshTaskRequest(identifier: "com.nexusguard.agent.refresh")
request.earliestBeginDate = Date(timeIntervalSinceNow: 30 * 60) // 30 minutes
try BGTaskScheduler.shared.submit(request)
```
### 7.2 Background Modes
Add to `Info.plist`:
```xml
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>processing</string>
<string>vpn-api</string>
</array>
```
## 8. Security Considerations
### 8.1 Key Storage
- WireGuard private keys stored in iOS Keychain (hardware-backed)
- Non-sensitive config in UserDefaults
- Never log keys or tokens
### 8.2 TLS
- Server communication over HTTPS (TLS 1.2+)
- Use `URLSession` with default TLS settings
- Certificate pinning (optional, future)
### 8.3 Hardware ID
- Use `identifierForVendor` for device identification
- Persists across app reinstalls until device factory reset
- Used for key derivation (HWID + salt)
## 9. Testing Strategy
### 9.1 Unit Tests
- Crypto: Decrypt known ciphertext with known key
- Config: Keychain read/write cycle
- Heartbeat: Parse server response
### 9.2 Integration Tests
- Provision → Tunnel → Heartbeat cycle
- Config change detection
- Tunnel rebuild on config change
### 9.3 UI Tests
- VPN toggle interaction
- Tab switching
- Settings save/load
### 9.4 Device Tests
- iPhone 12+ running iOS 16+
- NetworkExtension background operation
- Keychain access in background
## 10. Future Enhancements
### 10.1 Phase 2
- iPadOS support
- Widget for quick status
- Shortcuts integration
- Siri commands
### 10.2 Phase 3
- macOS Catalyst support
- Apple Watch companion
- CarPlay integration
## 11. References
- [Apple NetworkExtension Documentation](https://developer.apple.com/documentation/networkextension)
- [WireGuard for iOS](https://github.com/WireGuard/wireguard-apple)
- [CryptoKit Documentation](https://developer.apple.com/cryptokit/)
- [Background Tasks](https://developer.apple.com/documentation/backgroundtasks)
- [NexusGuard Server API](../../server-core/docs/)