Commit Graph

7 Commits

Author SHA1 Message Date
enricobuehler 17a262aace fix(host/deps): ring-only crypto — drop aws-lc-sys (fails to build on the Windows CI)
android / android (push) Has been cancelled
audit / bun-audit (push) Successful in 14s
apple / screenshots (push) Has been cancelled
apple / swift (push) Has been cancelled
arch / build-publish (push) Has been cancelled
audit / cargo-audit (push) Has been cancelled
deb / build-publish (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / web (push) Has been cancelled
ci / docs-site (push) Has been cancelled
ci / bench (push) Has been cancelled
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 21s
decky / build-publish (push) Successful in 32s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 21s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 19s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 20s
docker / deploy-docs (push) Has been cancelled
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Has been cancelled
flatpak / build-publish (push) Has been cancelled
release / apple (push) Has been cancelled
windows / build (aarch64-pc-windows-msvc) (push) Has been cancelled
windows / build (x86_64-pc-windows-msvc) (push) Has been cancelled
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Has been cancelled
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Has been cancelled
windows-host / package (push) Has been cancelled
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
The Windows host clippy CI broke building aws-lc-sys 0.41.0 (a heavy C dep that
cl.exe fails to compile on the runner). The host was the ONLY thing pulling it:
its rcgen used features=["aws_lc_rs"], and bare `rustls`/`tokio-rustls` take
the default (aws-lc-rs) backend, and gamestream/{mod,tls}.rs installed the
aws_lc_rs crypto provider explicitly — a pre-existing deviation from the
project's documented ring-only design (punktfunk-core + the client are ring).

Align the host to ring: rcgen/rustls/tokio-rustls pinned to the `ring` feature
(keeping tls12 for Moonlight/GameStream TLS-1.2 clients) and the two GameStream
provider installs switched to `rustls::crypto::ring::default_provider()`. Both
providers offer the same standard TLS 1.2/1.3 suites, so it's transparent to the
TLS paths; aws-lc-sys/aws-lc-rs leave the tree entirely (`cargo tree -i
aws-lc-sys` => no match). Not caused by the preceding log fix (that touched no
crypto deps / the lock).

Validated: cargo tree (aws-lc-sys gone, windows target, amf-qsv,qsv features) +
.21 host clippy -D warnings (--features nvenc) clean. Owed: GameStream on-glass
re-check with a real Moonlight client (low risk — same TLS suites, client is
already ring).
2026-07-17 22:21:23 +02:00
enricobuehler 11045a0f70 chore: consolidate parallel-session WIP (HOLD — do not push)
Local snapshot of intermingled in-flight work, committed to unblock the encode
refactor (a clean ffmpeg_win.rs for the vbv-dedup follow-on). These hunks span
the same files and can't be cleanly split here; the commit bundles three
distinct workstreams that each belong in their own PR:

  - logging rework (~43 files: level re-tiering, structured fields, `?e`,
    hot-path flood latches)
  - conflicting-host detection (detect.rs + detect/{linux,windows}.rs + wiring
    in main.rs/mgmt.rs/Cargo.toml/docs/packaging)
  - standby-sink DWM-stall attribution (windows/display_events.rs + capture/
    vdisplay wiring)

NOT verified as a combination. NOT to be pushed until the refactor is done and
these are re-verified and reorganized into their proper per-workstream PRs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 12:42:53 +02:00
enricobuehler 59e04aec99 chore(deps): drop unmaintained rustls-pemfile; axum-server 0.7 -> 0.8
axum-server was used only for the plain-HTTP nvhttp listener, but we enabled
its tls-rustls feature (HTTPS is hand-rolled over tokio-rustls) — and that
feature was what pulled the unmaintained rustls-pemfile (RUSTSEC-2025-0134).
Drop the feature, bump axum-server to 0.8 (0.8 also no longer pulls it), and
move our own PEM parsing in gamestream/tls.rs to rustls-pki-types' PemObject
(the same path punktfunk-core/quic.rs already uses), removing our direct
rustls-pemfile dep too.

Net: rustls-pemfile fully gone; dependency graph trimmed 547 -> 529 crates
(the tls-rustls feature also dragged in prettyplease + a wasm-tooling chain).
cargo audit now reports only audiopus_sys + paste (transitive, latest, no
successor). 108 host tests + clippy + fmt green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 06:32:58 +00:00
enricobuehler 46b82d4eee fix(host/security): close audit findings S1,#1,#4,#10,#12,#7,#6,S2-S6 (Linux/cross-platform)
Remediations from design/security-review-2026-06-28.md verified on Linux
(cargo check/clippy/test green; Windows-gated paths verify in CI):

- S1 [HIGH]: bump quinn-proto 0.11.14 -> 0.11.15 (RUSTSEC-2026-0185,
  pre-auth out-of-order STREAM reassembly memory exhaustion on the
  always-on default QUIC listener).
- #1 [HIGH]: remove the unauthenticated nvhttp `GET /pin` endpoint; the
  GameStream PIN is delivered ONLY via the bearer-gated mgmt API, so a
  network client can no longer submit its own displayed PIN and self-pair.
- #4 [HIGH->MED]: gate the unauthenticated RTSP/UDP media plane on a paired
  `/launch` and bind it to the launching client's source IP (threaded
  through the HTTPS handler), so an unpaired peer can neither start capture
  on an idle host nor ride a paired client's active launch.
- #12: bound concurrent parked pairing waiters (MAX_PARKED_WAITERS) so a
  pre-auth peer can't pin unbounded 300s handshakes. +regression test.
- #10: throttle the per-packet ENet control GCM-decrypt-failed warn
  (exponential backoff) so a junk flood can't spam the log.
- #7 [MED->LOW]: serialize all process-global env mutation on the
  session-setup path under a new vdisplay::ENV_LOCK (apply_session_env /
  apply_input_env / the launch-cmd set_var / the gamescope env read), so
  concurrent native sessions can't race set_var/getenv (data-race UB ->
  host-wide DoS). Full per-session SessionContext threading remains a
  follow-up for cross-session value confusion.
- #6 [MED]: move the gamescope EIS socket relay from world-writable /tmp to
  $XDG_RUNTIME_DIR (per-user 0700) and reject a symlinked relay file, so a
  local user can't intercept (keylog) or deny the remote session's input.
- S2: a malformed client Opus mic frame now drops that frame instead of
  tearing down the shared host-lifetime virtual mic (cross-session DoS).
- S3: track held buttons/keys in capped HashSets (was unbounded Vec with
  O(n) scans) so a paired client can't grow per-session input state.
- S5: reject fps==0/absurd at the open_video chokepoint (covers Hello,
  ANNOUNCE, Reconfigure) so the encoder time_base/pts math can't div-by-0.
- S6: bound the shared mic mpsc (drop-newest when full).
- S4: cap Epic launcher-cache reads (catcache.bin/.item) so a planted giant
  can't OOM the host during library enumeration.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 22:06:24 +00:00
enricobuehler 1e0d2e661f feat(host): Apollo-backlog hardening — cert gate, NVENC RFI, media QoS, async injector
A pass over the apollo-comparison backlog (re-verified against current code).
Lands four items end-to-end plus a Windows-DualSense scoping doc.

- #5/#92/#26 — GameStream paired-cert allow-list. tls.rs surfaces the verified
  peer cert to handlers (serve_https + PeerCertFingerprint, now shared with the
  mgmt API instead of duplicated); nvhttp gates /launch /resume /applist /cancel
  on AppState.paired and reports a real PairStatus; save_paired writes atomically
  (temp+rename). Closes the "mTLS accepts any client cert" hole. + regression test.

- #6/#51/#19/#22 — NVENC caps query -> reference-frame invalidation. nvenc.rs
  query_caps probes nvEncGetEncodeCaps (max dims / 10-bit / custom-VBV / RFI),
  rejecting over-range modes and degrading 10-bit->8-bit instead of an opaque
  InvalidParam. New Encoder::invalidate_ref_frames (default false -> caller
  keyframes); the Windows NVENC path implements real RFI (multi-ref DPB +
  nvEncInvalidateRefFrames, dedup + IDR-on-overflow). control.rs decodes the
  0x0301 lost-frame range (Apollo's IDX_INVALIDATE_REF_FRAMES) -> AppState.rfi_range
  -> encode loop, falling back to a keyframe. NOTE: the Windows NVENC impl is
  RTX-box/CI-pending (can't compile on Linux); adversarially reviewed vs the SDK.

- #43/#72 — media socket QoS + buffer growth. New punktfunk_core::transport::qos:
  grow_socket_buffers (factored out the native plane's 32MB SO_SNDBUF growth so the
  GameStream sockets reuse it) + set_media_qos (opt-in PUNKTFUNK_DSCP=1: DSCP CS5
  video / CS6 audio + Linux SO_PRIORITY, Apollo's scheme). Wired into UdpTransport
  and the GameStream video/audio sockets. Windows IP_TOS needs qWAVE (follow-up).

- #8/#45 — GameStream input injection off the ENet service thread. on_receive no
  longer injects inline (a slow inject head-blocked ENet keepalive/retransmit); it
  forwards to a dedicated injector thread. The hardened InjectorService moved from
  punktfunk1 into crate::inject (shared by both planes) + a coalesce step that sums
  adjacent relative-mouse/scroll deltas while preserving button/key/abs ordering.

Docs: re-verified apollo-comparison.md status (22 items already done/obsolete since
the snapshot) + windows-dualsense-scoping.md (ViGEm can't emulate a DualSense; real
DS5 on Windows needs a VHF virtual-HID driver — web-research pass pending).

fmt + clippy -D warnings clean; full workspace test suite green; no C-ABI/OpenAPI drift.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 00:06:30 +00:00
enricobuehler e2559101d0 feat(host/mgmt): mTLS auth — a paired client's cert authorizes the REST API
Phase 1 of moving the library off a manual mgmt token: the management API now serves
over HTTPS with the host's persistent identity (the cert clients already pin) and
OPTIONAL client-cert auth. A request is authorized if EITHER the peer presented a
client certificate whose SHA-256 is in the punktfunk/1 paired store (the same trust the
QUIC data plane uses — so a paired native client needs no token), OR it carries the
bearer token (the web console / admin). `/health` stays open.

axum-server can't surface the peer cert to a handler, so `serve_https` runs the rustls
handshake itself (tokio-rustls), reads the verified peer certificate, and serves the
axum Router over hyper with the fingerprint attached to each request; `require_auth`
checks it against `NativePairing::is_paired`. The verifier reuses the GameStream
AcceptAnyClientCert, parameterized to make client auth optional (a browser with no cert
still completes the handshake and falls back to the token).

Validated live: paired cert → 200, unpaired cert / no creds / bad token → 401, bearer
→ 200, /health open. (Note: the API is now HTTPS with a self-signed cert — a browser
shows a one-time trust prompt; native clients pin by fingerprint.)

Next: Apple client presents its identity over mTLS (drops the token field); embed the
web console; enable HTTPS mgmt by default.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 17:37:25 +00:00
enricobuehler 8cceb93541 rename: lumen → punktfunk, everywhere
Full project rename, decided 2026-06-10:
- Crates/binaries: punktfunk-core / punktfunk-host / punktfunk-client-rs.
- C ABI: punktfunk_* symbols, Punktfunk* types, include/punktfunk_core.h,
  PUNKTFUNK_FEATURE_QUIC guard (header regenerated; cbindgen renames updated, incl.
  PUNKTFUNK_BTN_*/PUNKTFUNK_AXIS_* wire constants).
- Protocol: punktfunk/1 — control-plane magic LMN1 → PKF1, nonce salt lmn1 → pkf1.
  WIRE BREAK: clients must be rebuilt from this revision.
- Env knobs: PUNKTFUNK_VIDEO_SOURCE / PUNKTFUNK_COMPOSITOR / PUNKTFUNK_ZEROCOPY / ….
- Host config dir: ~/.config/punktfunk (the box's dir was migrated in place — the
  persistent identity is unchanged, pinned fingerprints stay valid).
- Swift package: PunktfunkKit + PunktfunkCore.xcframework + PunktfunkConnection
  (Sources/PunktfunkClient app + tests renamed with it); build-xcframework.sh updated.
- scripts/: 60-punktfunk.rules, punktfunk-host.service; OpenAPI doc regenerated.

Also: scripts/headless/run-headless-kde.sh — full headless Plasma bringup. Root cause of
"desktop but no apps/settings" over the stream: plasmashell launched without
XDG_MENU_PREFIX=plasma-, so the launcher resolved a nonexistent applications.menu and
rendered an empty menu. The script sets the complete KDE session env (menu prefix,
KDE_FULL_SESSION, session version) and rebuilds ksycoca before starting plasmashell.

Gate: 97/97 tests, clippy -D warnings (both feature sets), fmt, C-ABI harness PASS,
zero lumen references left outside .git.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 13:11:59 +00:00