add TLS, service persistence, blocking panel, query types

- Local TLS: auto-generated CA + per-service certs (explicit SANs, not
  wildcards — browsers reject *.numa under single-label TLDs). HTTPS
  proxy on :443 via rustls/tokio-rustls. `numa install` trusts CA in
  macOS Keychain / Linux ca-certificates.
- Service persistence: user-added services saved to
  ~/.config/numa/services.json, survive restarts.
- Blocking panel: renamed "Check Domain" to "Blocking" with sources
  display, allowlist management UI, unpause button.
- Query types: recognize SOA, PTR, TXT, SRV, HTTPS (type 65) instead
  of logging as UNKNOWN.
- Blocklist gzip: reqwest now decompresses gzip responses from CDNs.
- Unified config_dir() in lib.rs for consistent path resolution under
  sudo and launchd. TLS certs use /usr/local/var/numa/ (writable as
  root daemon).
- Dashboard UX: panel subtitles differentiating overrides vs services,
  better placeholders, proxy route display, 600px query log height.
- Deploy: make deploy handles build+copy+codesign+restart cycle.
- Demo: scripts/record-demo.sh for recording hero GIF with CDP.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Razvan Dimescu
2026-03-21 01:15:07 +02:00
parent 10502f2db2
commit 3bfcd827ac
17 changed files with 1377 additions and 68 deletions

View File

@@ -14,7 +14,34 @@ pub mod question;
pub mod record;
pub mod service_store;
pub mod stats;
pub mod tls;
pub mod system_dns;
pub type Error = Box<dyn std::error::Error + Send + Sync>;
pub type Result<T> = std::result::Result<T, Error>;
/// Shared config directory: ~/.config/numa/
/// Handles sudo (uses SUDO_USER) and launchd (falls back to /usr/local/var/numa/).
pub fn config_dir() -> std::path::PathBuf {
// When run via sudo, SUDO_USER has the real user
if let Ok(user) = std::env::var("SUDO_USER") {
let home = if cfg!(target_os = "macos") {
format!("/Users/{}", user)
} else {
format!("/home/{}", user)
};
return std::path::PathBuf::from(home).join(".config").join("numa");
}
// Normal user (not root)
if let Ok(home) = std::env::var("HOME") {
let path = std::path::PathBuf::from(&home);
// /var/root on macOS is read-only (SIP), use /usr/local/var/numa instead
if !home.starts_with("/var/root") && !home.starts_with("/root") {
return path.join(".config").join("numa");
}
}
// Running as root daemon (launchd/systemd) — use system-wide path
std::path::PathBuf::from("/usr/local/var/numa")
}