From 43eae80b55e611340724e338f7f3936b82f9fe96 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Mon, 10 Mar 2025 18:52:42 -0400 Subject: [PATCH] feat(network): support for eap peap networks --- Cargo.lock | 2 +- cosmic-settings/Cargo.toml | 1 + cosmic-settings/src/pages/networking/wifi.rs | 118 ++++++++++++++++--- i18n/en/cosmic_settings.ftl | 1 + 4 files changed, 105 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9b58af8..d22db0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1771,7 +1771,7 @@ dependencies = [ [[package]] name = "cosmic-settings-subscriptions" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-settings-subscriptions#f666c7cfcad79547e55a368640784bca51081bd2" +source = "git+https://github.com/pop-os/cosmic-settings-subscriptions?branch=eap-peap#ad9c0d0d2df220b8c9336602be8458227e162b74" dependencies = [ "bluez-zbus", "cosmic-dbus-networkmanager", diff --git a/cosmic-settings/Cargo.toml b/cosmic-settings/Cargo.toml index 39ea1d2..a4b8473 100644 --- a/cosmic-settings/Cargo.toml +++ b/cosmic-settings/Cargo.toml @@ -90,6 +90,7 @@ num-derive = "0.4" [dependencies.cosmic-settings-subscriptions] git = "https://github.com/pop-os/cosmic-settings-subscriptions" +branch = "eap-peap" #TODO: only select features as needed features = ["network_manager", "pipewire", "pulse", "bluetooth"] optional = true diff --git a/cosmic-settings/src/pages/networking/wifi.rs b/cosmic-settings/src/pages/networking/wifi.rs index 534e985..8e53fb8 100644 --- a/cosmic-settings/src/pages/networking/wifi.rs +++ b/cosmic-settings/src/pages/networking/wifi.rs @@ -10,12 +10,17 @@ use anyhow::Context; use cosmic::{ iced::{Alignment, Length}, iced_core::text::Wrapping, - widget::{self, icon}, + iced_widget::focus_next, + widget::{self, column, icon}, Apply, Element, Task, }; use cosmic_settings_page::{self as page, section, Section}; use cosmic_settings_subscriptions::network_manager::{ - self, available_wifi::AccessPoint, current_networks::ActiveConnectionInfo, NetworkManagerState, + self, + available_wifi::{AccessPoint, NetworkType}, + current_networks::ActiveConnectionInfo, + hw_address::HwAddress, + NetworkManagerState, }; use futures::StreamExt; use secure_string::SecureString; @@ -36,6 +41,8 @@ pub enum Message { Disconnect(network_manager::SSID), /// An error occurred. Error(String), + /// Identity update from the dialog + IdentityUpdate(String), /// Create a dialog to ask for confirmation on forgetting a connection. ForgetRequest(network_manager::SSID), /// Forget a known access point. @@ -52,6 +59,8 @@ pub enum Message { SelectDevice(Arc), /// Opens settings page for the access point. Settings(network_manager::SSID), + /// Identity submitted from the dialog + SubmitIdentity, /// Toggles visibility of the password input TogglePasswordVisibility, /// Update NetworkManagerState @@ -81,6 +90,8 @@ enum WiFiDialog { Forget(network_manager::SSID), Password { ssid: network_manager::SSID, + hw_address: HwAddress, + identity: Option, password: SecureString, password_hidden: bool, }, @@ -135,6 +146,7 @@ impl page::Page for Page { self.dialog.as_ref().map(|dialog| match dialog { WiFiDialog::Password { password, + identity, password_hidden, .. } => { @@ -153,11 +165,25 @@ impl page::Page for Page { let secondary_action = widget::button::standard(fl!("cancel")).on_press(Message::CancelDialog); + let control: Element<_> = if let Some(identity) = identity { + column::column() + .spacing(8) + .push( + widget::text_input::text_input(fl!("identity"), identity) + .on_input(Message::IdentityUpdate) + .on_submit(|_| Message::SubmitIdentity), + ) + .push(password) + .into() + } else { + password.into() + }; + widget::dialog() .title(fl!("auth-dialog")) .icon(icon::from_name("preferences-wireless-symbolic").size(64)) .body(fl!("auth-dialog", "wifi-description")) - .control(password) + .control(control) .primary_action(primary_action) .secondary_action(secondary_action) .apply(Element::from) @@ -246,21 +272,28 @@ impl Page { } match req { - network_manager::Request::Password(ssid, _) => { + network_manager::Request::Authenticate { + ssid, + identity, + hw_address, + .. + } => { if success { - self.connecting.remove(&ssid); + self.connecting.remove(ssid.as_str()); } else { // Request to retry self.dialog = Some(WiFiDialog::Password { - ssid, + ssid: ssid.into(), + identity, + hw_address, password: SecureString::from(""), password_hidden: true, }); } } - network_manager::Request::SelectAccessPoint(ssid) => { - self.connecting.remove(&ssid); + network_manager::Request::SelectAccessPoint(ssid, hw_address, network_type) => { + self.connecting.remove(ssid.as_ref()); } _ => (), @@ -324,19 +357,54 @@ impl Page { Message::Connect(ssid) => { if let Some(nm) = self.nm_state.as_mut() { + let Some(ap) = nm + .state + .wireless_access_points + .iter() + .chain(nm.state.known_access_points.iter()) + .find(|ap| ap.ssid == ssid) + else { + return Task::none(); + }; self.connecting.insert(ssid.clone()); _ = nm .sender - .unbounded_send(network_manager::Request::SelectAccessPoint(ssid)); + .unbounded_send(network_manager::Request::SelectAccessPoint( + ssid, + ap.hw_address, + ap.network_type, + )); + } + } + + Message::IdentityUpdate(new_identity) => { + if let Some(WiFiDialog::Password { + ref mut identity, .. + }) = self.dialog + { + *identity = Some(new_identity); } } Message::PasswordRequest(ssid) => { - self.dialog = Some(WiFiDialog::Password { - ssid, - password: SecureString::from(""), - password_hidden: true, - }); + if let Some(nm) = self.nm_state.as_mut() { + let Some(ap) = nm + .state + .wireless_access_points + .iter() + .chain(nm.state.known_access_points.iter()) + .find(|ap| ap.ssid == ssid) + else { + return Task::none(); + }; + self.dialog = Some(WiFiDialog::Password { + ssid, + identity: matches!(ap.network_type, NetworkType::EAP).then(String::new), + hw_address: ap.hw_address, + password: SecureString::from(""), + password_hidden: true, + }); + } } Message::PasswordUpdate(pass) => { @@ -353,12 +421,24 @@ impl Page { return Task::none(); }; - if let WiFiDialog::Password { ssid, password, .. } = dialog { + if let WiFiDialog::Password { + ssid, + identity, + password, + hw_address, + .. + } = dialog + { if let Some(nm) = self.nm_state.as_mut() { self.connecting.insert(ssid.clone()); _ = nm .sender - .unbounded_send(network_manager::Request::Password(ssid, password)); + .unbounded_send(network_manager::Request::Authenticate { + ssid: ssid.to_string(), + identity, + hw_address, + password, + }); } } } @@ -414,6 +494,12 @@ impl Page { } } + Message::SubmitIdentity => { + if self.dialog.is_some() { + return focus_next(); + } + } + Message::WiFiEnable(enable) => { if let Some(nm) = self.nm_state.as_mut() { _ = nm diff --git a/i18n/en/cosmic_settings.ftl b/i18n/en/cosmic_settings.ftl index 782f5f8..b306ddd 100644 --- a/i18n/en/cosmic_settings.ftl +++ b/i18n/en/cosmic_settings.ftl @@ -34,6 +34,7 @@ remove = Remove settings = Settings username = Username visible-networks = Visible Networks +identity = Identity auth-dialog = Authentication Required .vpn-description = Enter the username and password required by the VPN service.