Linux dev builds: huddle mic still fails with NotAllowedError — trusted dev origin hardcoded to Vite default port 1420
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
## Summary
Huddles still fail on Linux dev builds with `NotAllowedError`, even though the
`getUserMedia`/WebKitGTK permission handling shipped in #3607 (which closed
#3495). The permission handler is installed and reachable, but its trusted
**dev** origin is hardcoded to Vite's default port `1420`, while every
just-based entrypoint serves the dev URL on a **per-worktree hashed port**.
The two never match, so the handler denies the mic request on every
`just dev` / `just desktop-standalone` launch.
The production origin (`tauri://localhost`) is unaffected — only the dev
build path is broken.
## Exact error
```
The request is not allowed by the user agent or the platform in the current
context, possibly because the user denied permission.
```
No OS permission prompt is shown (correct for Linux — WebKitGTK relies on the
embedding app's `permission-request` handler). The huddle companion window
opens, the mic `getUserMedia` rejects with `NotAllowedError`, and the huddle
tears down (TTS warmup → `cancellation reason=shutdown`, `DeviceSink` drops).
## Root cause
`desktop/src-tauri/src/linux_media.rs` trusts the dev origin as a compile-time
constant:
```rust
// linux_media.rs:34 (pre-fix)
#[cfg(debug_assertions)]
const DEV_ORIGIN: &str = "http://localhost:1420";
```
But `1420` is only the *default* in `vite.config.ts`
(`parseInt(process.env.VITE_PORT || "1420")`). The just-based entrypoints
always override it. `scripts/instance-env.sh:15` computes a stable per-worktree
port in the range **10000–64999** and exports it:
```bash
# scripts/instance-env.sh
BASE_PORT=$(python3 -c "import hashlib,sys; h=int(hashlib.sha256(sys.argv[1].encode()).hexdigest(),16); print(10000 + h % 55000)" "$WORKTREE_ROOT")
export BUZZ_VITE_PORT=$BASE_PORT
export VITE_PORT="$BUZZ_VITE_PORT"
DEV_URL="http://localhost:${BUZZ_VITE_PORT}"
# ...
BUZZ_TAURI_CONFIG="{\"build\":{\"devUrl\":\"${DEV_URL}\",\"beforeDevCommand\":\"exec ./node_modules/.bin/vite --port ${BUZZ_VITE_PORT} --strictPort\"}, ...}"
```
`just dev`, `just desktop-standalone`, `just staging`, and `just production`
all `source ../scripts/instance-env.sh` and pass `--config "$BUZZ_TAURI_CONFIG"`,
so the webview loads from `http://localhost:` — never `1420`.
`is_trusted_media_origin()` therefore returns `false` for the actual dev
origin, the handler calls `request.deny()`, and `getUserMedia` rejects with
`NotAllowedError`. The `1420` check is dead in practice because the just tasks
always set `VITE_PORT`.
## Repro
1. `just desktop-standalone` (or `just dev`) on Linux (WebKitGTK).
2. Start a huddle.
3. Mic `getUserMedia` rejects with the error above; huddle tears down.
Verified the same pubkey/identity and a working audio input device (mic is fine
in other apps); the failure is purely the origin check.
## Suggested fix
Derive the trusted dev origin from the actual dev port instead of hardcoding
`1420`. In debug builds only, read `VITE_PORT` (already exported by
`instance-env.sh` and inherited by the app) and build
`http://localhost:`, falling back to `http://localhost:1420` when the
variable is missing or invalid (a raw `pnpm tauri dev` without instance-env).
Keep the scheme + host hardcoded to `http://localhost` (only the port is
env-derived), keep exact-origin / path-prefix matching, keep deny-by-default,
and gate the whole dev path behind `#[cfg(debug_assertions)]` so packaged
builds remain unchanged.
## Environment
- Linux (Arch), WebKitGTK, native (non-AppImage) debug build via `just desktop-standalone`
- Introduced by: #3607 (merged 2026-07-30, "desktop: enable getUserMedia in the Linux WebKitGTK webview")
- Regresses: #3495
Contributor guide
Assessment
This issue has not been assessed yet.