feat: NostrVPN add-device guided wizard
All checks were successful
Build Archipelago ISO (dev) / build-iso (push) Successful in 14m28s
All checks were successful
Build Archipelago ISO (dev) / build-iso (push) Successful in 14m28s
Replace disconnected "Generate Invite" + "Add participant" with a 2-step wizard: enter phone npub → get invite QR + mesh details. Backend vpn.invite now accepts optional npub param to add participant in the same call. Modal shows network ID, node npub, and relay URLs for manual app configuration. Also includes nostr-vpn service hardening (rate-limit restarts, reset-failed before enable). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -240,7 +240,7 @@ impl RpcHandler {
|
||||
"vpn.status" => self.handle_vpn_status().await,
|
||||
"vpn.configure" => self.handle_vpn_configure(params).await,
|
||||
"vpn.disconnect" => self.handle_vpn_disconnect().await,
|
||||
"vpn.invite" => self.handle_vpn_invite().await,
|
||||
"vpn.invite" => self.handle_vpn_invite(params).await,
|
||||
"vpn.add-participant" => self.handle_vpn_add_participant(params).await,
|
||||
"vpn.create-peer" => self.handle_vpn_create_peer(params).await,
|
||||
"vpn.list-peers" => self.handle_vpn_list_peers().await,
|
||||
|
||||
@@ -240,7 +240,21 @@ impl RpcHandler {
|
||||
}
|
||||
|
||||
/// vpn.invite — Generate a NostrVPN invite URL + QR for the mobile app.
|
||||
pub(super) async fn handle_vpn_invite(&self) -> Result<serde_json::Value> {
|
||||
/// Optionally accepts `npub` param to add the phone as a participant in the same call.
|
||||
pub(super) async fn handle_vpn_invite(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<serde_json::Value> {
|
||||
// If an npub was provided, add it as a participant first
|
||||
if let Some(ref p) = params {
|
||||
if let Some(peer_npub) = p.get("npub").and_then(|v| v.as_str()) {
|
||||
if !peer_npub.is_empty() {
|
||||
// Reuse add-participant logic
|
||||
self.handle_vpn_add_participant(Some(serde_json::json!({ "npub": peer_npub }))).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read nvpn config to build invite
|
||||
let npub = vpn::read_nvpn_config_value("nostr", "public_key").await
|
||||
.ok_or_else(|| anyhow::anyhow!("No Nostr public key in nvpn config"))?;
|
||||
@@ -250,7 +264,7 @@ impl RpcHandler {
|
||||
|
||||
// Read relays from config
|
||||
let relays = vpn::read_nvpn_config_list("nostr", "relays").await;
|
||||
let relay_str = if relays.is_empty() {
|
||||
let relay_csv = if relays.is_empty() {
|
||||
"wss://relay.damus.io,wss://relay.primal.net".to_string()
|
||||
} else {
|
||||
relays.join(",")
|
||||
@@ -259,7 +273,7 @@ impl RpcHandler {
|
||||
// Build invite URL: nvpn://invite/<network_id>?npub=<npub>&relays=<csv>
|
||||
let invite_url = format!(
|
||||
"nvpn://invite/{}?npub={}&relays={}",
|
||||
network_id, npub, relay_str
|
||||
network_id, npub, relay_csv
|
||||
);
|
||||
|
||||
// Generate QR code
|
||||
@@ -274,6 +288,11 @@ impl RpcHandler {
|
||||
"qr_svg": svg,
|
||||
"npub": npub,
|
||||
"network_id": network_id,
|
||||
"relays": if relays.is_empty() {
|
||||
vec!["wss://relay.damus.io".to_string(), "wss://relay.primal.net".to_string()]
|
||||
} else {
|
||||
relays
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user