Skip to content

fix(web): make STUN URL configurable, default empty (#179)#472

Merged
intendednull merged 1 commit into
claude/friendly-maxwell-Oggvwfrom
auto-fix/issue-179-configurable-stun
Apr 28, 2026
Merged

fix(web): make STUN URL configurable, default empty (#179)#472
intendednull merged 1 commit into
claude/friendly-maxwell-Oggvwfrom
auto-fix/issue-179-configurable-stun

Conversation

@intendednull
Copy link
Copy Markdown
Owner

what

big rock: voice.rs had stun:stun.l.google.com:19302 hardcoded. every voice call shouted user IP at Google. bad.

now: STUN list come from window.__WILLOW_STUN_URLS. default = empty. empty list = no third-party STUN = no leak. voice ICE use host candidates + iroh relay path.

want Google STUN back? set the global. want self-host STUN? set the global. init.js has commented example.

why

privacy. fix #179 short-term rock. metadata leak gone by default. user must opt in to leak.

brainstorm

three rocks considered:

  • A: window.__WILLOW_STUN_URLS JS global — match existing window.__WILLOW_RELAY_URL rock. easy override, no rebuild. picked.
  • B: build-time env var — rebuild needed every flip. rejected.
  • C: query string param — show in URL, log spew, no match relay rock. rejected.

verify

  • cargo fmt --check — clean
  • cargo clippy --workspace --all-targets -- -D warnings — zero warnings
  • cargo test --workspace — all green
  • cargo check --target wasm32-unknown-unknown -p willow-web — clean

browser test runner (geckodriver/firefox) not in this env. tests added at crates/web/tests/browser.rs::stun_config:

  • default resolve_stun_urls() returns empty
  • override populates it
  • default RTCConfiguration has empty iceServers
  • override surfaces the URL

compile on wasm32 verified — runtime assertions will run on PR CI / just test-browser.

tradeoff

  • some browsers grumpy about totally empty iceServers? config still set explicitly to empty array (not undefined), which is spec-legal. if breaks, fallback rock = ship a self-hosted STUN default — file as follow-up if observed.
  • voice on hostile NATs may now fail without explicit STUN. user override knob exists. medium-term self-host STUN tracked under [security] Hardcoded Google STUN server leaks user IP metadata #179.

scope

short-term rock only. medium-term (self-host STUN) and long-term (iroh relay ICE) stay open under #179.

Refs #179


Generated by Claude Code

Hardcoded `stun:stun.l.google.com:19302` leaked every voice-call
participant's public IP to Google. Replace it with a configurable list
that defaults to empty — voice ICE now relies on host candidates plus
the iroh relay path, so no third-party server learns the user's IP
unless the deployment opts in.

Knob: `window.__WILLOW_STUN_URLS = ['stun:host:port', ...]`, mirroring
the existing `window.__WILLOW_RELAY_URL` override pattern in
`crates/web/init.js` / `app.rs::resolve_relay_url`. `init.js` ships the
override commented out alongside an example for restoring Google STUN
or pointing at a self-hosted server.

Brainstorm: chose the JS window global (Option A) over a build-time
env var (rebuild-required, less flexible) and over a query-string
override (exposed in URLs/logs, doesn't match the existing pattern).

Tests (`crates/web/tests/browser.rs::stun_config`):
  - default `resolve_stun_urls()` returns empty Vec
  - override populates the Vec
  - default `RTCConfiguration` has no `iceServers` entries
  - override surfaces the supplied URL in the config

Scope: short-term fix only. Self-hosted STUN (medium-term) and
iroh-relay-based ICE traversal (long-term) tracked under #179.

Refs #179
@intendednull intendednull merged commit 7fbe2c8 into claude/friendly-maxwell-Oggvw Apr 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants