fix(fips): fall back to upstream daemon npub on legacy/dev nodes

Nodes without a seed-derived FIPS key (legacy deploys, fresh pre-onboarding
installs) were reporting "Awaiting seed" in the dashboard even when the
upstream fips.service was running — status.npub was None unless
/data/identity/fips_key.pub existed.

- fips/service.rs: new read_upstream_npub() reads /etc/fips/fips.pub
  (bech32 text or raw 32 bytes) from the debian package.
- fips/mod.rs: FipsStatus::current() prefers the seed-derived npub,
  falls back to the upstream key. service_active is now TRUE if either
  archipelago-fips.service OR upstream fips.service is active; adds
  upstream_service_state to the status payload.
- fips/update.rs: resolve the upstream default branch from the GitHub
  repo API (jmcorgan/fips is on `master`, not `main`) instead of
  hardcoding — future repo rename just works.
- network/router.rs + api/rpc/router.rs: diagnostics gain wifi_ssid from
  `nmcli -t device` so the Network card can show the connected SSID.
- UI: Home.vue adds a FIPS row to the Local Network card; Server.vue
  mounts the new FipsNetworkCard and shows SSID + FIPS Mesh rows;
  HomeNetworkCard.vue removed (superseded by the inline rows).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-04-19 00:42:56 -04:00
co-authored by Claude Opus 4.7
parent 30a7f73ead
commit 6b42bfd503
9 changed files with 356 additions and 197 deletions
+31
View File
@@ -203,6 +203,35 @@ pub struct NetworkDiagnostics {
pub tor_connected: bool,
pub dns_working: bool,
pub recommendations: Vec<String>,
/// SSID of the currently-active WiFi connection, or None if the node is on
/// wired / no WiFi adapter / NetworkManager isn't around.
pub wifi_ssid: Option<String>,
}
/// Ask NetworkManager for the active WiFi SSID. Returns None silently if
/// nmcli is unavailable or no WiFi device is connected.
async fn active_wifi_ssid() -> Option<String> {
let out = tokio::process::Command::new("nmcli")
.args(["-t", "-f", "DEVICE,TYPE,STATE,CONNECTION", "device"])
.output()
.await
.ok()?;
if !out.status.success() {
return None;
}
let stdout = String::from_utf8_lossy(&out.stdout);
for line in stdout.lines() {
// DEVICE:TYPE:STATE:CONNECTION — colons inside fields are escaped by nmcli -t
let mut parts = line.split(':');
let _dev = parts.next()?;
let typ = parts.next().unwrap_or("");
let state = parts.next().unwrap_or("");
let conn = parts.next().unwrap_or("");
if typ == "wifi" && state == "connected" && !conn.is_empty() {
return Some(conn.to_string());
}
}
None
}
/// Run a comprehensive network diagnostic check.
@@ -211,6 +240,7 @@ pub async fn run_diagnostics() -> Result<NetworkDiagnostics> {
let upnp_available = check_upnp_available().await;
let tor_connected = check_tor_connectivity().await;
let dns_working = check_dns().await;
let wifi_ssid = active_wifi_ssid().await;
let nat_type = if wan_ip.is_some() {
if upnp_available {
@@ -246,6 +276,7 @@ pub async fn run_diagnostics() -> Result<NetworkDiagnostics> {
tor_connected,
dns_working,
recommendations,
wifi_ssid,
})
}