New SQLite table addressbook_audit_log records destructive and
mutating actions against the connections tree: create_folder,
update_folder, delete_folder, create_entry, update_entry,
delete_entry. Each row captures user_email, action, scope,
folder_path, optional entry_name, client IP, a small JSON details
blob, and created_at.
Details is deliberately headline-only: counts for delete_folder
(subfolders_deleted, entries_deleted), allowed_groups_count +
inherit_from_parent for folder writes, session type for entry
writes. Entry field values (password, private_key, hostname) and
full request bodies are never written. Audit rows live in SQLite,
not Vault, so logging content would leak Vault-only secrets onto
disk.
The six handlers in api.rs gain ConnectInfo + HeaderMap +
TrustedProxies + Db extractors so client IP can be resolved
through the existing auth::client_ip helper (respecting trusted
proxies) and the audit row can be written post-success.
New admin-only endpoint GET /api/admin/addressbook-audit mirrors
the existing token audit shape (limit + email filter, capped at
1000). admin.html gains a "Connections Audit Log" section below
the token audit, auto-loaded on page show.
cleanup_old_audit_log now also sweeps the new table on the same
retention window as token_audit_log.
Three pieces of v1.6.0 work that happened together and are easier to
review as one save point.
Rename: Address Book → Connections
- static/addressbook.html renamed to static/connections.html
- Nav links, page titles, empty states, onboarding, and prose updated
across all 8 static pages (connections, admin, docs, index,
recordings, reports, sessions, tokens).
- README, CLAUDE.md, and every file under docs/ updated.
- src/main.rs: connections.html added to the branded-page map and
route list; /addressbook.html returns a 308 permanent redirect so
existing bookmarks keep working.
- Backend API paths, Rust types, and Vault storage paths are
deliberately unchanged — internal only.
Folder allowed_groups picker
- New SQLite table `seen_groups` tracks OIDC groups observed in any
user login; OIDC callback upserts after extracting groups.
- `GET /api/auth/known-groups` (admin-only) returns the union of
group_role_mappings and seen_groups.
- `GET /api/addressbook/folders/{scope}/{folder}/config` adds the
missing endpoint the frontend was already calling — existing
allowed_groups now prefill the edit-folder modal.
- Folder modal swaps the free-text comma-separated input for a chip
picker with a themed combobox dropdown: autocomplete over known
groups, keyboard nav, "+ add custom" row for unlisted groups.
Active session visibility (GitHub #102)
- `GET /api/sessions` scopes to the caller's own sessions by default;
`?all=true` lets admins opt in (used by the Sessions page).
- `GET /api/sessions/{id}` and the thumbnail GET/PUT endpoints are
now owner-or-admin, returning 404 for other callers so session
existence isn't leaked.
- Connections' Active Sessions strip is now always owner-scoped —
admins still manage everyone via the Sessions page.
Frontend for #101 — subfolder support (backend landed in c2a3822) — plus
a site-wide visual overhaul extracted into a single shared stylesheet.
Address book
- Folder sidebar renders as a tree with lazy-loaded children via the
/api/addressbook/folders/{scope}/{path}/subfolders endpoint.
- Scope badge is now an icon with hover tooltip: ⊕ shared, ▣ instance.
- New "+ subfolder" button creates a nested folder under the selection.
- Move-entry dropdown includes any loaded subfolders.
- Batch folder API now returns path + has_children so the tree can
render chevrons without a second request per folder.
Design system (rustguac.css)
- Extracted ~700 lines of near-duplicate CSS from each page into a
shared stylesheet linked by every page.
- 18px body, strict 38/44/54px control heights, uppercase letter-spaced
section labels, zebra table rows, active-nav underline bar.
- Uniform button ladder: primary (red) / accent (connect, teal) /
ghost (+ buttons) / small (edit/delete chrome).
- Generic status colors, type badges, pagination, token-reveal,
summary cards, hop cards, and flow diagram now live in one place.
Per-page updates
- addressbook, admin, docs, index, recordings, reports, sessions,
tokens: style blocks reduced to page-specific layouts only.
- reports/recordings/sessions: bare <strong> page titles promoted
to <h2> for proper heading hierarchy.
- Stripped inline padding/font-size attributes that were overriding
the shared ladder.
- 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
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).
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.
Session history:
- New session_history SQLite table tracks all sessions with user,
entry, folder, hostname, duration, and recording file
- Automatic cleanup via session_history_retention_days config (default 90)
- 8 new unit tests for session history DB functions
Reports page (poweruser+ only):
- Summary cards: total sessions, hours, unique users, active now
- Sortable/filterable session history table with pagination
- Top Connections and Top Users leaderboards
- CSV export for session history with filters
Enriched recordings:
- Recording .meta sidecars now include user, folder, entry name, session type
- Recordings API returns enriched metadata from .meta files
- Recordings page shows User, Entry, Folder columns
Other:
- Reports nav link on all pages, hidden for operator/viewer roles
- Reports documentation in docs/reports.md
- Onboarding wizard for new users (role-scoped, dismissable)
- Settings menu label visibility improvement
- Fixed stale credential variable test (hyphen support)
Credential variables — address book entries reference $domain_username /
$domain_password instead of storing static credentials. Users fill in their
own values via My Credentials (gear menu), stored per-user in Vault KV.
All variables set → silent launch; missing → prompted. Hyphens allowed in
variable names. Docs section added.
Bug fixes:
- Rate limiting disabled by default; opt-in via rate_limit = true (#62)
- Docker: copy FreeRDP guac-common-svc plugins to runtime image (#64)
- Docker/install: add chromium-sandbox package for non-root web sessions (#61)
- Logo: skip redundant JS src= when server-side branding already set (#65)
- Sessions page: hide Open/Share buttons for non-active sessions (#63)
- Drive: expose drive_configured in /api/auth/status, warn in UI when
[drive] not configured
- install.sh: verify FreeRDP plugin installation
UI polish:
- Nav bar: border separator + spacing between header and nav on all pages
- Address book: password show/hide toggle on all password fields
- Drive diagnostic logging (session.rs, websocket.rs, client.html)
Closes#61, #62, #63, #64, #65
User API tokens allow OIDC users to authenticate via bearer token for
automation and scripting. Powerusers and admins can create their own
tokens; admins can create tokens for operators. Tokens use SHA-256
hashing, optional max_role caps, optional expiry, and full audit
logging of create/revoke operations with client IPs.
- DB schema: user_api_tokens and token_audit_log tables
- Auth middleware: validates user tokens as fallback after admin keys
- API: 7 new endpoints (self-service + admin token management)
- UI: tokens.html (self-service) + admin.html token/audit sections
- Nav: Tokens link added to all pages (visible for operator+)
- Docs: API reference, security model, roles/access control updated
- Background cleanup: expired tokens + 90-day audit log retention
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>