improv: network authentication

This commit is contained in:
Ashley Wulber 2026-01-28 20:35:01 -05:00 committed by Ashley Wulber
parent 2924fea3ac
commit f48bcde63b
3 changed files with 31 additions and 55 deletions

View file

@ -20,7 +20,6 @@ use cosmic_settings_network_manager_subscription::{
self as network_manager, NetworkManagerState, self as network_manager, NetworkManagerState,
available_wifi::{AccessPoint, NetworkType}, available_wifi::{AccessPoint, NetworkType},
current_networks::ActiveConnectionInfo, current_networks::ActiveConnectionInfo,
hw_address::HwAddress,
nm_secret_agent, nm_secret_agent,
}; };
use cosmic_settings_page::{self as page, Section, section}; use cosmic_settings_page::{self as page, Section, section};
@ -103,7 +102,6 @@ enum WiFiDialog {
Forget(network_manager::SSID), Forget(network_manager::SSID),
Password { Password {
ssid: network_manager::SSID, ssid: network_manager::SSID,
hw_address: HwAddress,
identity: Option<String>, identity: Option<String>,
password: SecureString, password: SecureString,
password_hidden: bool, password_hidden: bool,
@ -353,12 +351,7 @@ impl Page {
} }
match req { match req {
network_manager::Request::Authenticate { network_manager::Request::Authenticate { ssid, identity, .. } => {
ssid,
identity,
hw_address,
..
} => {
if success { if success {
self.connecting.remove(ssid.as_str()); self.connecting.remove(ssid.as_str());
} else { } else {
@ -366,7 +359,6 @@ impl Page {
self.dialog = Some(WiFiDialog::Password { self.dialog = Some(WiFiDialog::Password {
ssid: ssid.into(), ssid: ssid.into(),
identity, identity,
hw_address,
password: SecureString::from(""), password: SecureString::from(""),
password_hidden: true, password_hidden: true,
tx: Arc::new(Mutex::new(None)), tx: Arc::new(Mutex::new(None)),
@ -377,9 +369,9 @@ impl Page {
network_manager::Request::SelectAccessPoint( network_manager::Request::SelectAccessPoint(
ssid, ssid,
hw_address,
network_type, network_type,
_tx, _tx,
interface,
) => { ) => {
if success || matches!(network_type, NetworkType::Open) { if success || matches!(network_type, NetworkType::Open) {
self.connecting.remove(ssid.as_ref()); self.connecting.remove(ssid.as_ref());
@ -388,7 +380,6 @@ impl Page {
ssid, ssid,
identity: matches!(network_type, NetworkType::EAP) identity: matches!(network_type, NetworkType::EAP)
.then(String::new), .then(String::new),
hw_address,
password: SecureString::from(""), password: SecureString::from(""),
password_hidden: true, password_hidden: true,
tx: Arc::new(Mutex::new(None)), tx: Arc::new(Mutex::new(None)),
@ -499,9 +490,9 @@ impl Page {
.sender .sender
.unbounded_send(network_manager::Request::SelectAccessPoint( .unbounded_send(network_manager::Request::SelectAccessPoint(
ssid, ssid,
ap.hw_address,
ap.network_type, ap.network_type,
self.secret_tx.clone(), self.secret_tx.clone(),
self.active_device.as_ref().map(|d| d.interface.clone()),
)); ));
} }
} }
@ -528,7 +519,6 @@ impl Page {
self.dialog = Some(WiFiDialog::Password { self.dialog = Some(WiFiDialog::Password {
ssid, ssid,
identity: matches!(ap.network_type, NetworkType::EAP).then(String::new), identity: matches!(ap.network_type, NetworkType::EAP).then(String::new),
hw_address: ap.hw_address,
password: SecureString::from(""), password: SecureString::from(""),
password_hidden: true, password_hidden: true,
tx: Arc::new(Mutex::new(None)), tx: Arc::new(Mutex::new(None)),
@ -553,7 +543,6 @@ impl Page {
ssid, ssid,
identity, identity,
password, password,
hw_address,
tx, tx,
.. ..
} = dialog } = dialog
@ -562,6 +551,7 @@ impl Page {
self.connecting.insert(ssid.clone()); self.connecting.insert(ssid.clone());
let nm_sender = nm.sender.clone(); let nm_sender = nm.sender.clone();
let secret_tx = self.secret_tx.clone(); let secret_tx = self.secret_tx.clone();
let interface = self.active_device.as_ref().map(|d| d.interface.clone());
return Task::future(async move { return Task::future(async move {
let mut guard = tx.lock().await; let mut guard = tx.lock().await;
if let Some(tx) = guard.take() { if let Some(tx) = guard.take() {
@ -570,9 +560,9 @@ impl Page {
_ = nm_sender.unbounded_send(network_manager::Request::Authenticate { _ = nm_sender.unbounded_send(network_manager::Request::Authenticate {
ssid: ssid.to_string(), ssid: ssid.to_string(),
identity, identity,
hw_address,
password, password,
secret_tx, secret_tx,
interface,
}); });
} }
}) })
@ -718,7 +708,6 @@ impl Page {
ssid, ssid,
password: previous, password: previous,
password_hidden: true, password_hidden: true,
hw_address: ap.hw_address,
identity: matches!(ap.network_type, NetworkType::EAP).then(String::new), identity: matches!(ap.network_type, NetworkType::EAP).then(String::new),
tx, tx,
}); });
@ -736,7 +725,6 @@ impl Page {
ssid, ssid,
password, password,
identity, identity,
hw_address,
.. ..
}) = self.dialog.take() }) = self.dialog.take()
{ {
@ -746,7 +734,6 @@ impl Page {
tx: Arc::new(Mutex::new(None)), tx: Arc::new(Mutex::new(None)),
ssid, ssid,
identity, identity,
hw_address,
}); });
return task::message(Message::FocusSecureInput); return task::message(Message::FocusSecureInput);
} }

View file

@ -29,7 +29,6 @@ use futures::{
FutureExt, SinkExt, StreamExt, FutureExt, SinkExt, StreamExt,
channel::mpsc::{UnboundedReceiver, UnboundedSender, unbounded}, channel::mpsc::{UnboundedReceiver, UnboundedSender, unbounded},
}; };
use hw_address::HwAddress;
use iced_futures::{Subscription, stream}; use iced_futures::{Subscription, stream};
use secure_string::SecureString; use secure_string::SecureString;
use tokio::process::Command; use tokio::process::Command;
@ -45,8 +44,6 @@ pub type UUID = Arc<str>;
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum Error { pub enum Error {
#[error("access point not found")]
AccessPointNotFound,
#[error("failed to list bluetooth devices with rfkill")] #[error("failed to list bluetooth devices with rfkill")]
BluetoothRfkillList(std::io::Error), BluetoothRfkillList(std::io::Error),
#[error("failed to activate connection")] #[error("failed to activate connection")]
@ -299,8 +296,8 @@ async fn start_listening(
ssid, ssid,
identity, identity,
password, password,
hw_address,
secret_tx, secret_tx,
interface,
}) => { }) => {
let nm_state = NetworkManagerState::new(&conn).await.unwrap_or_default(); let nm_state = NetworkManagerState::new(&conn).await.unwrap_or_default();
@ -310,13 +307,13 @@ async fn start_listening(
&ssid, &ssid,
identity.as_deref(), identity.as_deref(),
Some(password.unsecure()), Some(password.unsecure()),
hw_address,
secret_tx.clone(), secret_tx.clone(),
if identity.is_some() { if identity.is_some() {
NetworkType::EAP NetworkType::EAP
} else { } else {
NetworkType::PSK NetworkType::PSK
}, },
interface.clone(),
) )
.await .await
.is_ok(); .is_ok();
@ -327,8 +324,8 @@ async fn start_listening(
ssid: ssid.clone(), ssid: ssid.clone(),
identity: identity.clone(), identity: identity.clone(),
password: password.clone(), password: password.clone(),
hw_address,
secret_tx: secret_tx.clone(), secret_tx: secret_tx.clone(),
interface,
}, },
success, success,
state: NetworkManagerState::new(&conn).await.unwrap_or_default(), state: NetworkManagerState::new(&conn).await.unwrap_or_default(),
@ -336,17 +333,10 @@ async fn start_listening(
.await; .await;
} }
Some(Request::SelectAccessPoint(ssid, hw_address, network_type, secret_tx)) => { Some(Request::SelectAccessPoint(ssid, network_type, secret_tx, interface)) => {
if matches!(network_type, NetworkType::Open) { if matches!(network_type, NetworkType::Open) {
attempt_wifi_connection( attempt_wifi_connection(&conn, ssid, network_type, output, None, interface)
&conn, .await;
ssid,
hw_address,
network_type,
output,
None,
)
.await;
} else { } else {
// For secured networks, check if we have saved credentials // For secured networks, check if we have saved credentials
let has_saved = has_saved_wifi_credentials(&conn, &ssid).await; let has_saved = has_saved_wifi_credentials(&conn, &ssid).await;
@ -359,10 +349,10 @@ async fn start_listening(
attempt_wifi_connection( attempt_wifi_connection(
&conn, &conn,
ssid, ssid,
hw_address,
network_type, network_type,
output, output,
secret_tx, secret_tx,
interface,
) )
.await; .await;
} }
@ -640,10 +630,10 @@ async fn has_saved_wifi_credentials(conn: &zbus::Connection, ssid: &str) -> bool
async fn attempt_wifi_connection( async fn attempt_wifi_connection(
conn: &zbus::Connection, conn: &zbus::Connection,
ssid: SSID, ssid: SSID,
hw_address: HwAddress,
network_type: NetworkType, network_type: NetworkType,
output: &mut futures::channel::mpsc::Sender<Event>, output: &mut futures::channel::mpsc::Sender<Event>,
secret_tx: Option<tokio::sync::mpsc::Sender<nm_secret_agent::Request>>, secret_tx: Option<tokio::sync::mpsc::Sender<nm_secret_agent::Request>>,
interface: Option<String>,
) { ) {
let state = NetworkManagerState::new(conn).await.unwrap_or_default(); let state = NetworkManagerState::new(conn).await.unwrap_or_default();
let success = if let Err(err) = state let success = if let Err(err) = state
@ -652,9 +642,9 @@ async fn attempt_wifi_connection(
ssid.as_ref(), ssid.as_ref(),
None, None,
None, None,
hw_address,
secret_tx, secret_tx,
network_type, network_type,
interface.clone(),
) )
.await .await
{ {
@ -666,7 +656,7 @@ async fn attempt_wifi_connection(
_ = request_response( _ = request_response(
conn, conn,
Request::SelectAccessPoint(ssid, hw_address, network_type, None), Request::SelectAccessPoint(ssid, network_type, None, interface),
success, success,
) )
.then(|event| output.send(event)) .then(|event| output.send(event))
@ -688,8 +678,8 @@ pub enum Request {
ssid: String, ssid: String,
identity: Option<String>, identity: Option<String>,
password: SecureString, password: SecureString,
hw_address: HwAddress,
secret_tx: Option<tokio::sync::mpsc::Sender<nm_secret_agent::Request>>, secret_tx: Option<tokio::sync::mpsc::Sender<nm_secret_agent::Request>>,
interface: Option<String>,
}, },
/// Get WiFi credentials for a known access point. /// Get WiFi credentials for a known access point.
GetWiFiCredentials( GetWiFiCredentials(
@ -705,9 +695,9 @@ pub enum Request {
/// Connect to a known access point. /// Connect to a known access point.
SelectAccessPoint( SelectAccessPoint(
SSID, SSID,
HwAddress,
NetworkType, NetworkType,
Option<tokio::sync::mpsc::Sender<nm_secret_agent::Request>>, Option<tokio::sync::mpsc::Sender<nm_secret_agent::Request>>,
Option<String>,
), ),
/// Toggle airplaine mode. /// Toggle airplaine mode.
SetAirplaneMode(bool), SetAirplaneMode(bool),
@ -907,9 +897,9 @@ impl NetworkManagerState {
ssid: &str, ssid: &str,
identity: Option<&str>, identity: Option<&str>,
password: Option<&str>, password: Option<&str>,
hw_address: HwAddress,
mut secret_tx: Option<tokio::sync::mpsc::Sender<nm_secret_agent::Request>>, mut secret_tx: Option<tokio::sync::mpsc::Sender<nm_secret_agent::Request>>,
network_type: NetworkType, network_type: NetworkType,
interface: Option<String>,
) -> Result<(), Error> { ) -> Result<(), Error> {
secret_tx = secret_tx.filter(|tx| !tx.is_closed()); secret_tx = secret_tx.filter(|tx| !tx.is_closed());
let nm = NetworkManager::new(conn).await?; let nm = NetworkManager::new(conn).await?;
@ -925,14 +915,6 @@ impl NetworkManagerState {
} }
} }
let Some(ap) = self
.wireless_access_points
.iter()
.find(|ap| ap.ssid.as_ref() == ssid && ap.hw_address == hw_address)
else {
return Err(Error::AccessPointNotFound);
};
let mut conn_settings: HashMap<&str, HashMap<&str, zvariant::Value>> = HashMap::from([ let mut conn_settings: HashMap<&str, HashMap<&str, zvariant::Value>> = HashMap::from([
( (
"802-11-wireless", "802-11-wireless",
@ -984,7 +966,8 @@ impl NetworkManagerState {
if !matches!( if !matches!(
device.device_type().await.unwrap_or(DeviceType::Other), device.device_type().await.unwrap_or(DeviceType::Other),
DeviceType::Wifi DeviceType::Wifi
) { ) || (interface.is_some() && interface != device.interface().await.ok())
{
continue; continue;
} }
@ -1010,7 +993,7 @@ impl NetworkManagerState {
let known_conn = if let Some(known_conn) = known_conn { let known_conn = if let Some(known_conn) = known_conn {
if secret_tx.is_none() || identity.is_some() { if secret_tx.is_none() || identity.is_some() {
known_conn.update(conn_settings).await?; known_conn.update(conn_settings).await.unwrap();
} }
known_conn known_conn
} else { } else {

View file

@ -147,6 +147,16 @@ async fn secret_agent_stream_impl(
msg_tx: futures::channel::mpsc::Sender<Event>, msg_tx: futures::channel::mpsc::Sender<Event>,
mut rx: tokio::sync::mpsc::Receiver<Request>, mut rx: tokio::sync::mpsc::Receiver<Request>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// fail early if we can't connect, closing the channel
{
let ss = secret_service::SecretService::connect(secret_service::EncryptionType::Dh)
.await
.map_err(|e| Arc::new(e))?;
let collection = ss.get_default_collection().await.map_err(|e| Arc::new(e))?;
if collection.is_locked().await.map_err(|e| Arc::new(e))? {
_ = collection.unlock().await.map_err(|e| Arc::new(e))?;
}
}
// register the secret agent with NetworkManager // register the secret agent with NetworkManager
let proxy = let proxy =
nm_secret_agent_manager::AgentManagerProxy::builder(&zbus::Connection::system().await?) nm_secret_agent_manager::AgentManagerProxy::builder(&zbus::Connection::system().await?)
@ -162,10 +172,6 @@ async fn secret_agent_stream_impl(
.await?; .await?;
proxy.register_with_capabilities(identifier, 1).await?; proxy.register_with_capabilities(identifier, 1).await?;
// fail early if we can't connect, closing the channel
let _ = secret_service::SecretService::connect(secret_service::EncryptionType::Dh)
.await
.map_err(|e| Arc::new(e))?;
while let Some(request) = rx.recv().await { while let Some(request) = rx.recv().await {
match request { match request {