fix: vpn.add-participant writes to root-owned daemon config via sudo

The nvpn daemon config at /var/lib/archipelago/nostr-vpn/ is owned by
root, but the backend runs as archipelago. Direct write silently failed,
so adding a second phone's npub never reached the daemon — service
restarted with stale config. Now falls back to sudo cp for root-owned
paths, and first-boot sets ownership to archipelago.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-04-08 16:25:39 +02:00
parent aa2a13d510
commit eebdade0d4
3 changed files with 22 additions and 4 deletions

2
core/Cargo.lock generated
View File

@@ -80,7 +80,7 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
[[package]]
name = "archipelago"
version = "1.3.1"
version = "1.3.4"
dependencies = [
"anyhow",
"archipelago-container",

View File

@@ -310,10 +310,26 @@ impl RpcHandler {
}
}
if let Ok(new_content) = toml::to_string_pretty(&table) {
if let Err(e) = tokio::fs::write(config_path, &new_content).await {
tracing::warn!("Failed to write {}: {}", config_path, e);
} else {
// Try direct write first; fall back to sudo cp for root-owned daemon config
if tokio::fs::write(config_path, &new_content).await.is_ok() {
info!("Added participant to {}", config_path);
} else {
// Write to temp file, then sudo cp to target
let tmp = format!("/tmp/.nvpn-config-{}", std::process::id());
if tokio::fs::write(&tmp, &new_content).await.is_ok() {
let cp = tokio::process::Command::new("sudo")
.args(["cp", &tmp, config_path])
.output().await;
let _ = tokio::fs::remove_file(&tmp).await;
match cp {
Ok(ref out) if out.status.success() => {
info!("Added participant to {} (via sudo)", config_path);
}
_ => {
tracing::warn!("Failed to write {} (even with sudo)", config_path);
}
}
}
}
}
}

View File

@@ -137,11 +137,13 @@ if command -v nvpn >/dev/null 2>&1; then
# Sync config to daemon HOME so the service finds it
# (service runs with HOME=/var/lib/archipelago/nostr-vpn)
# Owned by archipelago so the backend can update participants without sudo
DAEMON_CONFIG_DIR="/var/lib/archipelago/nostr-vpn/.config/nvpn"
mkdir -p "$DAEMON_CONFIG_DIR"
if [ -f "$NVPN_CONFIG_DIR/config.toml" ]; then
cp "$NVPN_CONFIG_DIR/config.toml" "$DAEMON_CONFIG_DIR/config.toml"
fi
chown -R archipelago:archipelago /var/lib/archipelago/nostr-vpn
# Ensure env file exists for the service
mkdir -p /var/lib/archipelago/nostr-vpn