232 Commits

Author SHA1 Message Date
Dave Kempe 8c248edb53 deps: update rustls-webpki 0.103.12 (RUSTSEC-2026-0098, 0099) v1.5.5 2026-04-16 17:34:10 +10:00
Dave Kempe 77c7c535f4 Docs cleanup, default theme to aurora, Vault install guidance
- Switch default theme from dark to aurora across server config,
  all 9 static HTML pages, example config, and docs
- Fix theme docs: list all 8 presets (was 6, missing jaguar/aurora),
  add missing type_vdi_bg/type_vdi_fg fields
- Add Vault/address book setup as recommended post-install step in
  installation docs — the address book is the primary user-facing
  feature and requires Vault
- Renumber subsequent install steps
2026-04-16 16:54:25 +10:00
Dave Kempe 84616f5730 Session limits and completed session cleanup (#99)
- Add max_sessions (default 500) and max_sessions_per_user (default 50)
  config options. Session creation is rejected with a clear error when
  limits are reached. Set to 0 for unlimited (backward compatible).
- Add background reaper that removes completed/error/expired sessions
  from the in-memory HashMap after session_cleanup_delay_secs (default
  300s). Session history in SQLite is not affected.
- Prevents resource exhaustion from unbounded session creation and
  memory leak from accumulated completed sessions.

Closes #99
v1.5.4
2026-04-12 07:40:32 +10:00
Dave Kempe 58ba74ff51 WebSocket Origin check: compare hostnames only, ignore ports
Avoids false rejections behind reverse proxies where the Host header
may include an explicit port (e.g. :443) that the browser's Origin
omits as a default port.
2026-04-12 07:23:57 +10:00
Dave Kempe 2074895e90 Security hardening: 7 audit findings fixed
From OWASP-based security audit (categories 2-12):

- Vault path traversal: validate folder names on read operations
  (get_folder_config, list_entries, get_entry) — write operations
  already validated but reads did not
- SSH host key: reject connection when stored key fails to parse,
  instead of silently accepting (was bypassing verification)
- Config secret redaction: custom Debug impls for OidcConfig and
  VaultConfig that redact client_secret, role_id, and client_key
- Branding XSS: HTML-escape site_title and logo_url config values
  before injecting into page templates
- WebSocket CSWSH: validate Origin header against Host header on
  WebSocket upgrade, reject cross-origin requests
- VDI bind mounts: add nosuid,nodev mount options to home directory
  bind mounts to prevent setuid binary attacks
- Recording access: restrict list/serve endpoints to poweruser+ role
  (previously any authenticated user including viewers could access
  all recordings)
2026-04-12 07:19:16 +10:00
Dave Kempe 622569290a Security hardening: share URL redaction, auth rate limiting, fixes
- Redact share_url from session listings for non-owners — previously
  any authenticated user could enumerate share tokens and join sessions
  they didn't create (share_url now only returned to session creator
  and admins)
- Always rate-limit OIDC login/callback (1/sec burst 5 per IP)
  regardless of rate_limit config, preventing brute-force on auth
- Fix disconnect instruction detection: use instruction boundary
  matching instead of substring contains — clipboard content or typed
  text containing "10.disconnect;" could falsely trigger VDI container
  destruction
- Restrict sudoers chown rule to rustguac:rustguac only, preventing
  arbitrary ownership changes on the LUKS mount point
v1.5.3
2026-04-11 21:49:03 +10:00
Dave Kempe a330c0cda0 deps: bump bollard 0.18 to 0.20, update VDI Docker driver
Bollard 0.20 moved container option types from bollard::container to
bollard::query_parameters, replaced Config<T> with ContainerCreateBody,
and changed several fields to Option types. Update all imports and call
sites in the VDI Docker driver accordingly.
2026-04-11 21:11:38 +10:00
Dave Kempe 07dbf874bd Merge pull request #96 from sol1/dependabot/cargo/russh-0.60.0
deps: bump russh from 0.59.0 to 0.60.0
2026-04-11 17:48:37 +10:00
dependabot[bot] 8bdd5ab115 deps: bump russh from 0.59.0 to 0.60.0
Bumps [russh](https://github.com/warp-tech/russh) from 0.59.0 to 0.60.0.
- [Release notes](https://github.com/warp-tech/russh/releases)
- [Commits](https://github.com/warp-tech/russh/compare/v0.59.0...v0.60.0)

---
updated-dependencies:
- dependency-name: russh
  dependency-version: 0.60.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-11 07:47:40 +00:00
Dave Kempe 267f082f11 Merge pull request #97 from sol1/dependabot/cargo/tokio-1.51.1
deps: bump tokio from 1.51.0 to 1.51.1
2026-04-11 17:46:35 +10:00
dependabot[bot] c6f560d75d deps: bump tokio from 1.51.0 to 1.51.1
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.51.0 to 1.51.1.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.51.0...tokio-1.51.1)

---
updated-dependencies:
- dependency-name: tokio
  dependency-version: 1.51.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-10 09:21:20 +00:00
Dave Kempe 22c3638d00 cargo fmt v1.5.2 2026-04-09 21:26:13 +10:00
Dave Kempe 958b675fd2 SSH tunnel: host key verification with UI-driven pinning
check_server_key no longer blindly accepts all keys. Jump hosts now
support a host_key field stored in Vault alongside credentials.

- New POST /api/ssh/probe-host-key endpoint probes an SSH server and
  returns its public key, fingerprint, and algorithm
- Address book UI: "Verify Host Key" button per jump host probes the
  server, shows fingerprint for confirmation, stores key on save
- TunnelHandler verifies the server key against the stored key on
  connect — rejects with detailed error on mismatch
- Unpinned keys accepted with TOFU warning log for backward compat
- host_key preserved through credential merging on entry update

Closes #95
2026-04-09 21:22:36 +10:00
Dave Kempe f43738f54a H.264: remove frame dropping, sync gating approach only
Frame dropping at queue depth 5 triggered during normal operation and
broke the H.264 reference chain, corrupting output until the next
keyframe. Remove frame dropping entirely — sync gating alone provides
sufficient flow control by delaying the sync response until decodes
complete, giving guacd accurate backpressure.
v1.5.1
2026-04-09 07:59:03 +10:00
Dave Kempe 175c30b705 H.264: fix unbounded stream lag via sync gating and frame dropping
The H.264 decode path bypassed the Guacamole sync mechanism — the sync
response fired immediately without waiting for WebCodecs to finish
decoding. guacd thought the client was keeping up and sent at full rate,
causing the decode queue to grow without bound (30+ seconds of lag
observed over time).

Fix: gate the sync response on H.264 decode completion so guacd gets
real backpressure. Also drop delta frames when the decode queue exceeds
5 frames as a safety valve for transient overload (tab backgrounding).

- Add pending-decode tracking and per-frame position capture to
  H264Decoder.js (fixes shared mutable state race)
- Add waitForPending() with 1s safety timeout for sync gating
- Add frame dropping when decodeQueueSize > 5 (never drops keyframes)
- Add stats() method for console debugging (__guac_client._h264Decoder.stats())
- Gate sync response in Client.js on H.264 decode completion

Closes #93
2026-04-08 07:21:23 +10:00
Dave Kempe 2e046ea4a8 OIDC: native CA trust, custom CA cert, TLS skip-verify, better errors
Switch reqwest from rustls-tls-webpki-roots to rustls-tls-native-roots
so the OS trust store is used by default — private CAs installed
system-wide now work without extra config.

Add ca_cert and tls_skip_verify options to [oidc] for environments
where the system store isn't available or for debugging TLS issues.
Improve OIDC discovery error formatting to surface the actual cause
(issuer mismatch, TLS failure, etc.) instead of opaque "Request failed".

Closes #94
2026-04-08 06:31:14 +10:00
Dave Kempe 5c7eb84886 README overhaul: badges, VDI, updated features, remove RHEL
- GitHub badges (CI, release, license, Docker pulls)
- VDI featured in architecture, features, and quick start
- Feature tables for session types, security, connectivity
- Removed RPM/RHEL references (build from source for others)
- Complete docs index with all current pages
- Cleaner quick start with Docker+VDI instructions
2026-04-06 08:25:00 +10:00
Dave Kempe 75eae2b43f cargo fmt v1.5.0 2026-04-05 10:33:01 +10:00
Dave Kempe fb0f965bb2 Fix nav: Logout + Settings float right together on all pages
Logout link moved inside the float-right user-menu-wrapper so both
Logout and Settings appear on the far right of the nav bar. Fixed
addressbook.html Settings font size to match other pages (1.3em).
2026-04-05 10:20:10 +10:00
Dave Kempe 318725e8db Config docs: add [recording] and [vdi] sections, missing fields
- [recording] section: enabled, max_disk_percent, max_recordings, rotation
- [vdi] section: full reference with all 8 fields, prerequisites link
- Added missing top-level fields: rate_limit, session_history_retention_days
2026-04-05 10:03:06 +10:00
Dave Kempe c48be9ed3f Move Logout button out of Settings dropdown on all pages
Logout is now a standalone nav link next to Settings (Logout Settings
order, right-aligned). Applied consistently across all 7 HTML pages.
Removed Logout from the settings dropdown menu.
2026-04-05 10:01:35 +10:00
Dave Kempe a9a966e675 VDI: detect image change and clear stale thumbnails
- start_or_reuse checks if existing container's image differs from
  the requested image. If so, stops the old container and creates
  a new one with the new image.
- Clear stale VDI thumbnail when starting a new session, so old
  screenshots don't linger from previous images/failed sessions.
2026-04-05 08:33:42 +10:00
Dave Kempe 7283cdb2d7 Dockerfile: VDI support (commented out, documented)
- Run example with Docker socket mount and group-add for VDI
- Commented-out [vdi] section in default config template
- vdi-homes directory and volume for persistent home dirs
- No changes to default behavior — VDI stays disabled unless configured
2026-04-05 08:29:21 +10:00
Dave Kempe 6a2a759abf Docs: VDI prerequisites — Docker install and usermod instructions
Installation guide and VDI docs page now document that Docker must be
installed separately and rustguac user added to docker group manually.
2026-04-05 08:27:21 +10:00
Dave Kempe 985a9de45c Overview docs: add VDI references throughout
VDI mentioned alongside SSH/RDP/VNC/Web in: intro, why section,
similarities, architecture description, tunnel section.
2026-04-05 08:16:57 +10:00
Dave Kempe 9114e2b78e Add VDI to overview docs page
Architecture diagram, session type section, comparison table,
project structure, and docs index updated with VDI references.
2026-04-05 08:13:56 +10:00
Dave Kempe 3d39685f58 Add VDI documentation page
Comprehensive docs covering: config, image requirements, address book
setup, container lifecycle, persistent homes, active sessions,
per-entry settings, security notes.
2026-04-05 08:11:00 +10:00
Dave Kempe c0e194fa6a v1.5.0: VDI Docker desktop containers
Major release adding ephemeral Docker desktop containers (VDI), session
thumbnails with active sessions UI, and session-ended overlay.

VDI:
- New session type: VDI (Docker) — per-user ephemeral desktop containers
- VdiDriver trait for downstream extensibility (JumpboxVDI)
- DockerDriver: bollard API, deterministic naming, start/reuse/stop
- Container lifecycle: persist after disconnect, reap after idle timeout
- Per-entry idle timeout override via address book
- Persistent home dirs via bind mount (home_base config)
- Server disconnect detection (10.disconnect;) stops container on logout
- Test image: contrib/vdi-test-image (Debian + xrdp + xfce4)

Thumbnails & Active Sessions:
- Client captures display screenshot every 10s (JPEG, 320px)
- Active Sessions section in address book with thumbnail grid
- Dormant VDI containers shown with last captured thumbnail
- Click thumbnail to reconnect via address book connect flow

UI:
- Session ended overlay with Reconnect/Close buttons (all session types)
- Sessions page: collapsible ad-hoc form, VDI option
- Logout button moved out of settings dropdown

Security:
- Thumbnail endpoints require authentication
- JPEG magic byte validation on upload
- Path traversal protection on container thumbnails
- Env var name/value validation for containers
- Home base path traversal check

Dependencies:
- Added bollard 0.18 (Docker API client)
- Updated russh 0.59, tokio 1.51, toml 1.1.2, libc 0.2.184
2026-04-05 08:09:02 +10:00
Dave Kempe bf19574a0d Update docs: VDI architecture in CLAUDE.md, test image README
- CLAUDE.md: VDI session type, Docker architecture, VdiDriver trait,
  container lifecycle, config options, test image reference
- contrib/vdi-test-image/README.md: build, usage, image requirements
- Fix: RDP was missing from session types description
2026-04-05 08:07:07 +10:00
Dave Kempe b5566f7ce8 Security hardening for VDI and thumbnails
- Move thumbnail endpoints to authenticated routes (was unauthenticated)
- Validate JPEG magic bytes on thumbnail upload
- Require session to exist before accepting thumbnail
- Path traversal protection on VDI container thumbnail endpoint
- Validate container env var names (alphanumeric + underscore only)
- Reject env var values containing newlines
- Path traversal check on home_base bind mount
2026-04-05 08:05:34 +10:00
Dave Kempe 8567d93c4f Sessions page: collapsible ad-hoc form, VDI option
- New Session form collapsed by default (click to expand)
- Added VDI (Docker) to session type dropdown with container image field
- Jump hosts hidden for VDI sessions (local containers)
2026-04-05 07:59:38 +10:00
Dave Kempe 3273e47bbc VDI: per-entry idle timeout for containers
Address book entries can now set container_idle_timeout_mins to override
the global idle_timeout_mins. Stored as a Docker label on the container
so the reaper reads it without needing session state. Reaper also cleans
up VDI thumbnails when removing idle containers.
2026-04-05 07:55:50 +10:00
Dave Kempe 697b6f7d75 Active Sessions with thumbnails, dormant VDI containers
Client captures display thumbnail every 10s (JPEG, 320px), uploads
to server. Address book shows "Active Sessions" section with thumbnail
grid — click to reconnect via address book connect flow.

- PUT/GET /api/sessions/{id}/thumbnail endpoints
- GET /api/vdi/containers — list running VDI containers for current user
- VDI container labels: rustguac.entry, rustguac.image for reconnect
- Thumbnail copied to container-keyed file on disconnect (persists)
- Dormant VDI containers shown with last thumbnail
- Cache-busting on thumbnail images for live updates
- Moved logout button out of settings dropdown
- Fixed: VDI containers endpoint in authenticated route group
- Fixed: thumbnail click uses address book connect (not stale session URL)
2026-04-05 07:51:00 +10:00
Dave Kempe 8ff256f5df Session ended overlay with Reconnect/Close buttons
Show a centered overlay when the Guacamole client disconnects or
errors, instead of leaving a frozen canvas. Offers Reconnect (reload)
and Close (navigate to home) buttons. Applies to all session types.
2026-04-05 07:18:26 +10:00
Dave Kempe bfadf34a9b VDI: detect server-side disconnect to stop container on logout
Sniff for guacd's 10.disconnect; instruction in the proxy stream to
distinguish server-initiated disconnects (user logout, crash) from
browser-initiated disconnects (tab close, network drop).

- Logout from desktop → container stopped and removed immediately
- Tab close / network drop → container persists for reconnection
- Normal RDP/SSH/VNC sessions unaffected (flag only acted on for VDI)
2026-04-05 07:03:34 +10:00
Dave Kempe 690997d4eb VDI: persistent home dirs and logout stops container
- Add home_base config: bind-mounts {home_base}/{username} into container
  so user files persist across container restarts
- When guacd ends the connection (user logout / session crash), stop and
  remove the VDI container immediately
- Browser disconnect (tab close, network drop) keeps container running
  for reconnection — idle reaper handles eventual cleanup
2026-04-05 06:44:33 +10:00
Dave Kempe 501bd14a0d VDI Docker driver: ephemeral container desktops
Add 5th session type (Vdi) that spawns Docker containers with xrdp
and connects via RDP through guacd. Containers persist after disconnect
for configurable idle timeout, allowing reconnection to same desktop.

- VdiDriver trait (dyn-compatible) for downstream extensibility
- DockerDriver: bollard API, deterministic container naming per user,
  start/reuse/stop lifecycle, TCP+settle readiness polling
- Background reaper removes idle containers after timeout
- Address book: container_image, cpu/mem limits, env vars fields
- Config: [vdi] section with enabled, docker_socket, limits, timeouts
- Test image: contrib/vdi-test-image (Debian trixie + xrdp + xfce4)
2026-04-05 06:28:03 +10:00
Dave Kempe bcf203e79a Merge pull request #91 from sol1/dependabot/cargo/libc-0.2.184
deps: bump libc from 0.2.183 to 0.2.184
2026-04-04 06:06:54 +00:00
Dave Kempe e6a4aded80 Merge pull request #92 from sol1/dependabot/cargo/toml-1.1.2spec-1.1.0
deps: bump toml from 1.1.0+spec-1.1.0 to 1.1.2+spec-1.1.0
2026-04-04 06:06:47 +00:00
Dave Kempe 9d201bcf00 Merge pull request #89 from sol1/dependabot/cargo/tokio-1.51.0
deps: bump tokio from 1.50.0 to 1.51.0
2026-04-04 06:06:42 +00:00
Dave Kempe fabf6b75a7 Merge pull request #90 from sol1/dependabot/cargo/russh-0.59.0
deps: bump russh from 0.58.1 to 0.59.0
2026-04-04 06:06:15 +00:00
dependabot[bot] f0d28a8498 deps: bump toml from 1.1.0+spec-1.1.0 to 1.1.2+spec-1.1.0
Bumps [toml](https://github.com/toml-rs/toml) from 1.1.0+spec-1.1.0 to 1.1.2+spec-1.1.0.
- [Commits](https://github.com/toml-rs/toml/compare/toml-v1.1.0...toml-v1.1.2)

---
updated-dependencies:
- dependency-name: toml
  dependency-version: 1.1.2+spec-1.1.0
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-03 09:17:18 +00:00
dependabot[bot] 81a75fd783 deps: bump libc from 0.2.183 to 0.2.184
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.183 to 0.2.184.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.184/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.183...0.2.184)

---
updated-dependencies:
- dependency-name: libc
  dependency-version: 0.2.184
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-03 09:17:07 +00:00
dependabot[bot] addbd8d6b9 deps: bump russh from 0.58.1 to 0.59.0
Bumps [russh](https://github.com/warp-tech/russh) from 0.58.1 to 0.59.0.
- [Release notes](https://github.com/warp-tech/russh/releases)
- [Commits](https://github.com/warp-tech/russh/commits/v0.59.0)

---
updated-dependencies:
- dependency-name: russh
  dependency-version: 0.59.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-03 09:16:55 +00:00
dependabot[bot] 178964e85a deps: bump tokio from 1.50.0 to 1.51.0
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.50.0 to 1.51.0.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.50.0...tokio-1.51.0)

---
updated-dependencies:
- dependency-name: tokio
  dependency-version: 1.51.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-03 09:16:43 +00:00
Dave Kempe faf941eb06 Pin guacamole-server to known-good commit 2980cf0
Upstream GUACAMOLE-2221 introduced -Werror=maybe-uninitialized failure.
Pin all build paths (CI, Dockerfile, install.sh) to last known-good commit.
Update guacd version deliberately, not on every upstream push.
v1.0.2
2026-04-01 10:33:48 +11:00
Dave Kempe 836db3c9ec Fix window title: entry name persists after site_title loads 2026-04-01 09:39:50 +11:00
Dave Kempe 5d938c6009 v1.0.2: entry name in window title, recordings page enriched 2026-04-01 09:21:33 +11:00
Dave Kempe 9f7cc820dc Recordings page: show entry/user/type/folder, search, sortable columns 2026-04-01 08:59:51 +11:00
Dave Kempe ef1f194838 Show address book entry name in session window title 2026-03-31 15:55:12 +11:00