P5: settings, persistence, polkit packaging, README

Backend
- regenerate_identity command stops the daemon, deletes
  priv_key.bin, leaves the user to restart for a fresh identity;
  falls back to the canonical XDG path when sidecar.key_path()
  isn't populated yet
- tauri.conf.json ships the polkit policy via deb.files mapping;
  src-tauri/packaging/polkit/tech.threefold.mycellium-ui.policy
  declares the spawn action with auth_admin_keep so the dialog
  appears once per session

Frontend
- config store persists SidecarConfig (peers, tunName, noTun)
  through tauri-plugin-store; App.vue reads it and forwards to
  start_daemon, replacing the hard-coded defaults
- Settings view: daemon-config form, identity panel with the
  destructive regenerate button, sidecar log viewer, About
- README rewritten end-to-end: HTTP-loopback architecture, polkit
  install path, build commands, verification matrix, and a
  honest "known limitations" section
This commit is contained in:
syoul
2026-04-25 23:15:35 +02:00
parent f28d0e1338
commit eb86fdd182
10 changed files with 519 additions and 15 deletions

View File

@@ -247,3 +247,52 @@ pub async fn topic_forward_remove(state: State<'_, AppState>, topic_b64: String)
pub async fn lookup_pubkey(state: State<'_, AppState>, ip: String) -> AppResult<PubkeyLookup> {
require_client(&state)?.lookup_pubkey(&ip).await
}
// ─── Identity ────────────────────────────────────────────────────────────────
/// Stops the daemon (if running), removes the saved private key file, and
/// returns the daemon to the idle state. The caller restarts the daemon
/// to provoke regeneration.
#[tauri::command]
pub async fn regenerate_identity(state: State<'_, AppState>) -> AppResult<()> {
state.poller.stop();
let key_path = state.sidecar.key_path();
state.sidecar.stop().await;
if let Some(path) = key_path {
if path.exists() {
std::fs::remove_file(&path).map_err(AppError::from)?;
}
} else {
// Sidecar never started; resolve the canonical path via app_data_dir.
if let Some(p) = default_key_path() {
if p.exists() {
std::fs::remove_file(&p).map_err(AppError::from)?;
}
}
}
Ok(())
}
fn default_key_path() -> Option<std::path::PathBuf> {
// Best-effort: fall back to the same XDG location the sidecar uses.
dirs_like_app_data().ok().map(|d| d.join("priv_key.bin"))
}
fn dirs_like_app_data() -> std::io::Result<std::path::PathBuf> {
// We can't reach the AppHandle here, so we mirror Tauri's path:
// $XDG_DATA_HOME/<identifier>/ or $HOME/.local/share/<identifier>/.
let identifier = "tech.threefold.mycellium-ui";
if let Ok(d) = std::env::var("XDG_DATA_HOME") {
return Ok(std::path::PathBuf::from(d).join(identifier));
}
if let Ok(home) = std::env::var("HOME") {
return Ok(std::path::PathBuf::from(home)
.join(".local/share")
.join(identifier));
}
Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
"no app data dir",
))
}