Skip to content

feat(config): add api_version config for versioned signaling paths#36

Open
TerryHowe wants to merge 1 commit into
ShiftinBits:mainfrom
TerryHowe:feat/api-versioning
Open

feat(config): add api_version config for versioned signaling paths#36
TerryHowe wants to merge 1 commit into
ShiftinBits:mainfrom
TerryHowe:feat/api-versioning

Conversation

@TerryHowe
Copy link
Copy Markdown
Contributor

Summary

  • Adds server.api_version config field (default "v1") that prefixes all signaling server HTTP/WS paths — e.g., /auth/token becomes /v1/auth/token
  • Old clients with api_version = "" continue using unversioned paths with no change; new installs default to v1 automatically
  • HMAC signing auto-detects formula from path prefix: /v1/ paths use the nonce-based formula (timestamp:nonce:pathname), legacy paths use the original formula (timestamp:pathname)

Configuration

[server]
url = "https://signal.pmux.io"
api_version = "v1"   # default; set to "" for legacy paths

Or via env: PMUX_API_VERSION=v1

How it works

cfg.APIBaseURL() returns serverURL + "/" + apiVersion (e.g., https://signal.pmux.io/v1). This is passed to all HTTP/WS call sites (ExchangeToken, InitiatePairing, WaitForPairComplete, DeletePairing, DeleteDevice, SignalingClient, PeerManager). Function signatures are unchanged — callers supply the already-prefixed URL as the existing serverURL argument.

cfg.ServerURL() (no prefix) is preserved for QR code payloads and user-facing display.

SignRequest / SignWebSocketHeaders detect the formula from the path: if it starts with /v1/, they generate a nonce, set pmux-nonce, and sign with timestamp:nonce:path; otherwise they use the legacy formula.

Files changed

File Change
internal/config/config.go APIVersion field, APIBaseURL() method, PMUX_API_VERSION env var, validation, docs
internal/auth/hmac.go generateNonce(), computeHMACv1(), path-based formula selection in SignRequest / SignWebSocketHeaders
internal/agent/agent.go Use cfg.APIBaseURL() for SignalingClient and PeerManager
internal/agent/pair.go Use cfg.APIBaseURL() for API calls; keep cfg.ServerURL() for QR and warnings
internal/agent/unpair.go Use cfg.APIBaseURL()
internal/agent/uninstall.go Use cfg.APIBaseURL()

Test plan

  • go build ./... passes
  • go vet ./... passes
  • go test ./... passes
  • Config tests: default "v1", file/env override, explicit "" override, APIBaseURL() formatting
  • HMAC tests: v1 paths get nonce header, legacy paths don't; nonce uniqueness; v1 formula differs from legacy

Coordinated with server-side PR: ShiftinBits/pmux-server#25

🤖 Generated with Claude Code

Introduce a server.api_version setting (default "v1", env PMUX_API_VERSION)
that prefixes every HTTP/WebSocket call to the signaling server with the
configured version. Legacy deployments pass api_version = "" to keep the
unversioned paths.

Auto-select the HMAC formula from the request path: /v1/ paths use
timestamp:nonce:path with a pmux-nonce header; everything else keeps the
legacy timestamp:path formula. This lets callers upgrade transparently
just by passing the versioned base URL to the existing helpers.

cfg.ServerURL() still returns the bare host URL for QR payloads and
user-facing display. cfg.APIBaseURL() is the new value threaded to
SignalingClient, PeerManager, InitiatePairing, ExchangeToken,
WaitForPairComplete, DeletePairing, and DeleteDevice so every wire call
picks up the prefix automatically without any new function parameters.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Terry Howe <terrylhowe@gmail.com>
@snyk-io
Copy link
Copy Markdown

snyk-io Bot commented Apr 20, 2026

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

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