Replace C Tor with Rust Arti for Tor integration

- Replace C Tor (0.4.8.21) with Rust Arti (1.9.0/arti-client 0.38)
- 70% smaller binary: 21MB xcframework vs 67MB (6.9MB vs 14MB per slice)
- Memory-safe Rust implementation with modern async (tokio)
- Same SOCKS5 proxy interface at 127.0.0.1:39050 for drop-in compatibility
- FFI wrapper (arti-bitchat crate) with C-compatible exports
- Swift TorManager maintains identical public API
- Aggressive size optimization: opt-level=z, lto=fat, panic=abort, strip
- Supports iOS device, iOS simulator (Apple Silicon), and macOS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
jack
2026-01-13 16:18:00 -10:00
co-authored by Claude Opus 4.5
parent 7b9ffe464a
commit 23d63ab4df
2260 changed files with 6907 additions and 354558 deletions
@@ -0,0 +1,63 @@
import Foundation
#if os(macOS)
import CFNetwork
#endif
/// Provides a shared URLSession that routes traffic via Tor's SOCKS5 proxy
/// when Tor is enforced/ready. Allows swapping between proxied and direct
/// sessions so UI can toggle Tor usage at runtime.
public final class TorURLSession {
public static let shared = TorURLSession()
// Default (no proxy) session for direct Nostr access when Tor is disabled.
private var defaultSession: URLSession = TorURLSession.makeDefaultSession()
// Proxied (SOCKS5) session that routes through Tor.
private var torSession: URLSession = TorURLSession.makeTorSession()
private var useTorProxy: Bool = true
public var session: URLSession {
useTorProxy ? torSession : defaultSession
}
// Recreate sessions so new clients bind to the fresh SOCKS/control ports after a Tor restart.
public func rebuild() {
defaultSession = TorURLSession.makeDefaultSession()
torSession = TorURLSession.makeTorSession()
}
public func setProxyMode(useTor: Bool) {
guard useTorProxy != useTor else { return }
useTorProxy = useTor
rebuild()
}
private static func makeTorSession() -> URLSession {
let cfg = URLSessionConfiguration.ephemeral
cfg.waitsForConnectivity = true
// Keep in sync with TorManager defaults
let host = "127.0.0.1"
let port = 39050
#if os(macOS)
cfg.connectionProxyDictionary = [
kCFNetworkProxiesSOCKSEnable as String: 1,
kCFNetworkProxiesSOCKSProxy as String: host,
kCFNetworkProxiesSOCKSPort as String: port
]
#else
// iOS: CFNetwork SOCKS proxy keys are unavailable at compile time.
cfg.connectionProxyDictionary = [
"SOCKSEnable": 1,
"SOCKSProxy": host,
"SOCKSPort": port
]
#endif
return URLSession(configuration: cfg)
}
private static func makeDefaultSession() -> URLSession {
let cfg = URLSessionConfiguration.default
cfg.waitsForConnectivity = true
return URLSession(configuration: cfg)
}
}