Skip to content

fix: hide web mic button in non-secure contexts + tailscale recipe#31

Merged
cjus merged 2 commits into
mainfrom
carlos/solrac-mic-secure-context
May 18, 2026
Merged

fix: hide web mic button in non-secure contexts + tailscale recipe#31
cjus merged 2 commits into
mainfrom
carlos/solrac-mic-secure-context

Conversation

@cjus
Copy link
Copy Markdown
Owner

@cjus cjus commented May 18, 2026

Why

v0.10.0 ships voice support, but navigator.mediaDevices is undefined in non-secure contexts (anything other than HTTPS or http://localhost). On a default SOLRAC_WEB_HOST=0.0.0.0 deploy, opening the UI via a LAN IP / Tailscale 100.x address over HTTP shows the mic button, then throws Cannot read properties of undefined (reading 'getUserMedia') on click.

Two fixes:

  1. Client feature-detect. Split the single voiceFeatureAvailable flag into two: server-side voice availability (controls speak buttons + voice badge — both work over plain HTTP) and micCaptureAvailable (server voice AND browser exposes the mic API). Mic button hides itself when the browser can't capture; one-time toast explains. Speak buttons keep working in non-secure contexts since <audio> doesn't need them.

  2. Doc the operational fix. Tailscale serve is the cleanest single-tenant path to a real cert. Recipe lives in docs/SETUP.md §13 (first-time setup), docs/USAGE.md §Web UI (general access from other devices), docs/USAGE.md §Voice surface (mic-specific), and docs/RUNBOOK.md (diagnosis flow).

Files

  • public/app.jshasMicCaptureSupport() helper; micCaptureAvailable flag; one-shot toast; onMicClick gated on the new flag.
  • docs/USAGE.md — secure-context note in Voice surface + new "Reaching the UI from other devices" subsection.
  • docs/SETUP.md — Tailscale serve recipe in the web UI enablement step (replaces the vague "consider Tailscale" line).
  • docs/RUNBOOK.md — new "Web UI mic button hidden / getUserMedia undefined" section with diagnosis + three recovery paths.

Anti-goal status

None reversed. Tailscale is one of three documented options (localhost / Tailscale / reverse proxy with TLS) — recommended for single-tenant, not required.

Test plan

  • Insecure origin (http://<lan-ip>:7134/) — mic hidden, toast fires, no console exception, speak buttons work
  • Toast is one-shot (doesn't repeat on subsequent refreshVoiceState)
  • Localhost (http://localhost:7134/) — mic visible, no toast, STT round-trip writes voice_events row
  • Speak button replay hits cached blob (no second /api/tts call)
  • Voice badge toggle still works (click → /voice off → badge disappears)
  • Tailscale serve end-to-end — https://<host>.<tailnet>.ts.net/ shows real Let's Encrypt cert, mic works from another device on the tailnet

@cjus cjus merged commit 552b544 into main May 18, 2026
1 check passed
@cjus cjus deleted the carlos/solrac-mic-secure-context branch May 18, 2026 22:55
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.

1 participant