Files
bitchat/docs/TOR-INTEGRATION.md
T
jack 37d655d065 feat(tor): Tor-by-default scaffold and integration
- Add TorManager with static/dlopen start, torrc generation, SOCKS probe
- Add TorURLSession; route Nostr/Web fetches via SOCKS proxy
- Add chat system messages for Tor status; show progress (macOS) and ready
- Disable ControlPort bootstrap monitor on iOS; keep it on macOS
- Make Tor waits non-blocking; avoid main-actor stalls on startup
- Queue & flush Nostr subscriptions on relay connect; skip duplicates
- Always rewrite torrc at launch to fix iOS container path mismatches
- Link libz; add project wiring for tor-nolzma.xcframework
- Minor fixes: SOCKS probe resumeOnce guard, entitlement for network.server (macOS)
2025-09-07 13:52:07 +02:00

3.6 KiB
Raw Blame History

Tor-by-default integration (scaffold)

Overview

  • All network traffic is routed via a local Tor SOCKS5 proxy by default, with fail-closed behavior when Tor isnt ready. There are no user-visible settings.
  • This repo now includes a minimal TorManager and TorURLSession to make dropping in an embedded Tor framework straightforward.

Key pieces

  • TorManager
    • Boots Tor, manages a DataDirectory under Application Support, exposes SOCKS at 127.0.0.1:39050, and provides awaitReady().
    • Fails closed by default until Tor is bootstrapped. For local development only, define BITCHAT_DEV_ALLOW_CLEARNET to bypass Tor.
  • TorURLSession
    • Provides a shared URLSession configured with a SOCKS5 proxy when Tor is enforced/ready.
    • NostrRelayManager and GeoRelayDirectory now use this session and await Tor readiness before starting network activity.

Dropin steps

  1. Build or obtain a small Tor framework

    • Recommended: Tor C (client-only) with static linking and dead-strip.
    • Configure Tor with a minimal feature set: ./configure
      --enable-static
      --disable-asciidoc --disable-unittests --disable-manpage
      --disable-zstd --disable-lzma --enable-zlib
      --disable-systemd --disable-ptrace --disable-seccomp CFLAGS="-Os -fdata-sections -ffunction-sections"
      LDFLAGS="-Wl,-dead_strip"
    • Build a tiny OpenSSL/LibreSSL (no engines, strip symbols) or reuse system crypto where permitted on macOS.
  2. Add the framework to Xcode targets

    • Drop your xcframework into Frameworks/. The project is prewired in project.yml to link/embed Frameworks/tor-nolzma.xcframework (rename yours to match, or update the path).
    • Ensure the binary includes the slices you need (iOS device/simulator and/or macOS). If your xcframework lacks simulator slices, you can still build/run on device or macOS arm64; simulator will fail to link.
    • On iOS, it will be embedded and signed automatically.
  3. Wire Tor bootstrap in TorManager.startTor()

    • Two paths are already implemented:
      • If a module named Tor is present (iCepa API), it starts TORThread directly.
      • Otherwise, it attempts a dynamic load (dlopen) of a bundled framework binary named tor-nolzma.framework/tor-nolzma (or Tor.framework/Tor), resolves tor_run_main, and launches Tor on a background thread.
    • TorManager writes a torrc and then probes 127.0.0.1:39050 until ready.
  4. Verify networking

    • On app launch, TorManager.startIfNeeded() is called implicitly by awaitReady().
    • NostrRelayManager.connect() awaits readiness, then creates WebSocket tasks via TorURLSession.shared.
    • GeoRelayDirectory.fetchRemote() awaits readiness, then fetches via TorURLSession.shared.
  5. Optional macOS optimization

    • Detect a system Tor binary (e.g., /opt/homebrew/bin/tor) and run it as a subprocess to avoid bundling. Keep the embedded fallback for portability.

torrc template The generated torrc (under Application Support/bitchat/tor/torrc) is:

DataDirectory /bitchat/tor ClientOnly 1 SOCKSPort 127.0.0.1:39050 ControlPort 127.0.0.1:39051 CookieAuthentication 1 AvoidDiskWrites 1 MaxClientCircuitsPending 8

Dev bypass (local only)

  • To temporarily allow direct network without Tor for local development:
    • Add Swift compiler flag: BITCHAT_DEV_ALLOW_CLEARNET
    • This enables a clearnet session in TorURLSession when Tor isnt present.
    • Never enable this in release builds.

Notes

  • We intentionally do not change any app-level APIs: consumers simply use TorURLSession via existing code paths.
  • When Tor is missing in release builds, the app will not connect (fail-closed), logging a clear reason.