@@ -590,32 +590,27 @@ impl NetworkModule { |
| 590 | 590 | |
| 591 | 591 | /// Connect to a WiFi network with a password |
| 592 | 592 | pub fn connect_with_password(&mut self, ssid: &str, password: &str) -> Result<()> { |
| 593 | | - let conn = match &self.conn { |
| 594 | | - Some(c) => c, |
| 595 | | - None => anyhow::bail!("No D-Bus connection"), |
| 596 | | - }; |
| 597 | | - |
| 598 | 593 | if !self.state.wifi_available || !self.state.wifi_enabled { |
| 599 | 594 | anyhow::bail!("WiFi not available or not enabled"); |
| 600 | 595 | } |
| 601 | 596 | |
| 602 | 597 | info!("Connecting to WiFi network with password: {}", ssid); |
| 603 | 598 | |
| 604 | | - // Get the WiFi device |
| 605 | | - let wifi_device = match self.get_wifi_device(conn) { |
| 606 | | - Some(d) => d, |
| 607 | | - None => anyhow::bail!("No WiFi device found"), |
| 608 | | - }; |
| 609 | | - |
| 610 | | - // Find the access point to get security info |
| 611 | | - let ap = self.state.access_points.iter() |
| 612 | | - .find(|ap| ap.ssid == ssid) |
| 613 | | - .ok_or_else(|| anyhow::anyhow!("Access point not found: {}", ssid))?; |
| 614 | | - |
| 615 | | - let ap_path = ap.path.clone(); |
| 616 | | - let security = ap.security.clone(); |
| 599 | + // Use nmcli which handles secrets properly |
| 600 | + // nmcli device wifi connect <SSID> password <password> |
| 601 | + let output = std::process::Command::new("nmcli") |
| 602 | + .args(["device", "wifi", "connect", ssid, "password", password]) |
| 603 | + .output() |
| 604 | + .context("Failed to run nmcli")?; |
| 617 | 605 | |
| 618 | | - self.add_and_activate_connection_with_password(conn, ssid, password, &security, &wifi_device, &ap_path) |
| 606 | + if output.status.success() { |
| 607 | + info!("Successfully connected to {}", ssid); |
| 608 | + Ok(()) |
| 609 | + } else { |
| 610 | + let stderr = String::from_utf8_lossy(&output.stderr); |
| 611 | + warn!("nmcli failed: {}", stderr); |
| 612 | + anyhow::bail!("Failed to connect: {}", stderr.trim()) |
| 613 | + } |
| 619 | 614 | } |
| 620 | 615 | |
| 621 | 616 | /// Check if a network requires a password (is secured) |
@@ -813,6 +808,10 @@ impl NetworkModule { |
| 813 | 808 | let mut connection: HashMap<&str, Value> = HashMap::new(); |
| 814 | 809 | connection.insert("type", Value::Str("802-11-wireless".into())); |
| 815 | 810 | connection.insert("id", Value::Str(ssid.into())); |
| 811 | + // Set as user-owned connection so secrets can be saved without root |
| 812 | + let user = std::env::var("USER").unwrap_or_else(|_| "user".to_string()); |
| 813 | + let permissions = vec![Value::Str(format!("user:{}:", user).into())]; |
| 814 | + connection.insert("permissions", Value::Array(permissions.into())); |
| 816 | 815 | |
| 817 | 816 | let mut wireless: HashMap<&str, Value> = HashMap::new(); |
| 818 | 817 | // SSID as byte array |
@@ -831,6 +830,9 @@ impl NetworkModule { |
| 831 | 830 | }; |
| 832 | 831 | wireless_security.insert("key-mgmt", Value::Str(key_mgmt.into())); |
| 833 | 832 | wireless_security.insert("psk", Value::Str(password.into())); |
| 833 | + // Set psk-flags to 0 (NM_SETTING_SECRET_FLAG_NONE) so NM uses the embedded password |
| 834 | + // instead of asking a secret agent |
| 835 | + wireless_security.insert("psk-flags", Value::U32(0)); |
| 834 | 836 | |
| 835 | 837 | // Also set security reference in wireless settings |
| 836 | 838 | wireless.insert("security", Value::Str("802-11-wireless-security".into())); |