config visibility, PR review fixes, XSS hardening

Config visibility:
- startup banner shows config path, data dir, services path
- config search: ./numa.toml → ~/.config/numa/ → /usr/local/var/numa/
- /stats API exposes config_path and data_dir, dashboard footer renders them
- GET /ca.pem endpoint serves CA cert for cross-device TLS trust
- load_config returns ConfigLoad with found flag, warns on not-found
- ServerCtx stores PathBuf for config_dir/data_dir, string conversion at boundaries

PR review fixes:
- add explicit parens in resolve_route operator precedence (service_store.rs)
- hostname portability: drop -s flag, trim domain with split('.') (lan.rs)
- serve_ca uses spawn_blocking instead of sync fs::read in async handler
- load_config: remove TOCTOU exists() check, read directly and handle NotFound

XSS hardening:
- HTML-escape all user-controlled interpolations in dashboard (service names,
  route paths, ports, URLs, block check domain/reason)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Razvan Dimescu
2026-03-23 12:24:21 +02:00
parent 10f1602803
commit c6b35045d8
7 changed files with 126 additions and 27 deletions

View File

@@ -29,9 +29,9 @@ impl ServiceEntry {
.iter()
.filter(|r| {
request_path == r.path
|| request_path.starts_with(&r.path)
|| (request_path.starts_with(&r.path)
&& (r.path.ends_with('/')
|| request_path.as_bytes().get(r.path.len()) == Some(&b'/'))
|| request_path.as_bytes().get(r.path.len()) == Some(&b'/')))
})
.max_by_key(|r| r.path.len());