Skip to content

Internal browser: SOCKS-routed preview profiles per environment (true-origin previews, Phase 2) #69

Closed

Description

@mubeda

Summary

Give each remote environment's internal-browser previews a SOCKS-routed preview profile (the Orca model), so pages load at their true origin (http://localhost:5173) on every topology the desktop can tunnel, with cookies, OAuth redirects (including response_mode=form_post), and CORS behaving exactly as on the server. This is Phase 2 ("fidelity") of the internal-browser roadmap: an upgrade over the preview gateway, not a replacement.

Current state

  • Preview gateway (Phase 1, feat: internal browser preview gateway (Phase 1) #60) reaches server-loopback dev servers on LAN/WSL/SSH and browser mode, but gives each target a new origin (http://<server>:<gateway port> or http://127.0.0.1:<random>).
  • SSH same-port (feat/preview-ssh-same-port) keeps the real origin over desktop SSH when the local port is free, and makes the gateway cookie SameSite=Lax so GET OAuth callbacks work. Remaining gaps it cannot close: busy local ports (falls back to a new origin), form_post OAuth callbacks, LAN/WSL (always a new origin), and anything the gateway rewrites.
  • Per-environment preview storage already exists (same branch, spec §6): the local environment keeps preview-profile / bibcodepreview01; every other environment has its own profile (preview-profiles/<hash> or a macOS data store), each held by one long-lived native preview host (recreating child webviews disconnected the app). That is the profile boundary a per-environment proxy needs.

Research (from docs/plans/2026-10-06-internal-browser-and-mobile-emulator-research.md §2.4 (a), §2.6)

  • WebviewBuilder::proxy_url(http|socks5) exists (tauri-2.11.5/src/webview/mod.rs:1002-1013) but wry applies it to the profile/data store, not the view:

    Engine How wry applies it Consequence
    WebView2 appends --proxy-server=… to the environment's browser args (wry-0.55.1/src/webview2/mod.rs:304-317) needs its own data_directory (now true per environment). Chromium bypasses loopback implicitly → must pass --proxy-bypass-list=<-loopback> through additional_browser_args (Windows-only, replaces wry defaults that must be re-added)
    WebKitGTK website_data_manager.set_network_proxy_settings(Custom, …) with an empty ignore list (wry-0.55.1/src/webkitgtk/mod.rs:267-278) per WebContext (per profile); loopback handling unverified
    WKWebView KVC proxyConfigurations on WKWebsiteDataStore (wry-0.55.1/src/wkwebview/mod.rs:326-343) behind wry mac-proxy = Tauri macos-proxy feature (not enabled in BiBCode) per data store (now per environment); macOS 14+; loopback handling unverified
  • SOCKS endpoint per topology: SSH: ssh -D 127.0.0.1:<port> on the desktop's managed connection (like today's -L children in apps/desktop/src-tauri/src/ssh.rs). LAN/WSL/relay: a new tunnel RPC (Orca's network.browserTunnel), i.e. a new protocol surface carried over the typed WebSocket RPC.

  • Security: a loopback SOCKS listener is reachable by any local process; Orca makes it CONNECT-only on loopback (orca/src/main/browser/remote-browser-socks-server.ts:60,104-107). DNS-prefetch and WebRTC can leak around the proxy and need a policy.

  • Browser mode gets nothing (no webview) — the gateway stays the browser-mode path.

  • Blockers: Linux child-webview geometry (wry moves children only under X11 or a gtk::Fixed parent; tauri#10420/#16132/#15656), the macOS feature flag, the WebView2 bypass list.

Recommended plan (design document first)

  1. Spike (throwaway): on each engine, a preview profile with a SOCKS proxy to a test server — confirm loopback is proxied (WebView2 with <-loopback>, WebKitGTK empty ignore list, WKWebView proxyConfigurations), and that DNS resolves through the proxy (socks5h-like behaviour).
  2. Design doc: routing policy (which environments/URLs use SOCKS vs gateway; fallback to the gateway when the tunnel is down), profile lifecycle (proxy is fixed at environment creation → recreate-free host per environment already in place), tunnel RPC shape (auth scope orchestration:operate, per-connection flow control, limits), SOCKS server hardening (CONNECT-only, loopback, per-environment credentials if possible), leak policy (DNS prefetch off, WebRTC off for proxied profiles), macOS feature enablement.
  3. Desktop: enable macos-proxy; per-environment proxy_url; WebView2 additional_browser_args with the bypass list; a CONNECT-only loopback SOCKS server (Rust, no sidecar) bridging to ssh -D (SSH) or the tunnel RPC (others).
  4. Server: tunnel RPC (network.browserTunnel-like) that opens loopback TCP connections on the server for an authorized environment, with bounded buffers and backpressure; reuse admission/limits patterns from the gateway.
  5. Web: resolver chooses "load canonical URL directly" for SOCKS-routed environments; gateway remains the fallback and the browser-mode path.
  6. Docs/runbooks for every engine and topology.

Security considerations

  • CONNECT-only, loopback-only SOCKS listener; consider per-environment auth so one environment's profile cannot route through another's tunnel.
  • Tunnel RPC must only reach the server's loopback (or an explicit allowlist), never arbitrary hosts, unless deliberately designed.
  • Leak policy for DNS prefetch and WebRTC in proxied profiles.

Open questions

  1. Is SOCKS worth it given the gateway + SSH same-port coverage? (The research says "only if Phase 1 falls short" — collect cases: form_post OAuth, LAN/WSL origin, busy ports.)
  2. Tunnel RPC over the existing typed RPC (base64 JSON, stop-and-wait streams) vs a dedicated authenticated binary WebSocket (a carve-out to the typed-RPC rule)?
  3. Linux: fix child-webview geometry (gtk::Fixed) first, or ship SOCKS without Linux?

Acceptance criteria

  • On Windows, macOS 14+, and Linux desktops, a preview of http://localhost:5173 from an SSH, LAN, WSL, or relay environment loads at http://localhost:5173 through that environment, with OAuth form_post callbacks and CORS allowlists working.
  • Loopback on the client is never reached by a proxied profile; DNS and WebRTC leak tests pass.
  • Turning SOCKS off (or a tunnel failure) falls back to the gateway with an actionable notice.
  • Tests: SOCKS server unit tests, tunnel RPC tests, per-engine proxy configuration tests; native validation report per OS.

References

  • docs/plans/2026-10-06-internal-browser-and-mobile-emulator-research.md §2.4 (a), §2.6, §5 Phase 2 item 10
  • docs/superpowers/specs/2026-10-09-preview-ssh-same-port-design.md §6 (per-environment preview storage)
  • apps/desktop/src-tauri/src/preview/host.rs, apps/desktop/src-tauri/src/ssh.rs, apps/web/src/browser/previewGateway.ts

Activity

  1. mubeda commented on Oct 15, 2026

    @mubeda
    OwnerAuthor

    Shipped in v0.9.3 for the Linux desktop (ec1c5e3, 464c481, 1715a40, 80ddab9).

    • The server tunnels a preview's loopback connections over the environment's own RPC connection (preview.tunnelOpen/Write/Read/Close); it only ever dials 127.0.0.1 and ::1.
    • On Linux, a remote environment's preview profile routes loopback hosts (localhost, *.localhost, 127.0.0.0/8, ::1, and the wildcard binds 0.0.0.0 and ::) through a per-environment SOCKS server, so the page loads at its real origin (http://localhost:5173, HTTPS included). Other hosts connect from this computer, as an unproxied browser would.
    • Only sockets owned by the signed-in account may use the SOCKS server (checked against /proc/net/tcp*).

    Closing as shipped for Linux. Windows (WebView2) and macOS (WKWebView) profiles are not built yet; please open a new issue against v0.9.3 for each platform when you want them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementRequested improvement or new capability.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions