fix(vpn): retry username/pw entry dialog if connection fails
This commit is contained in:
parent
df71f293b8
commit
44a1a9ab90
1 changed files with 81 additions and 13 deletions
|
|
@ -40,6 +40,8 @@ pub enum Message {
|
||||||
Deactivate(ConnectionId),
|
Deactivate(ConnectionId),
|
||||||
/// An error occurred.
|
/// An error occurred.
|
||||||
Error(ErrorKind, String),
|
Error(ErrorKind, String),
|
||||||
|
/// VPN connection error.
|
||||||
|
VpnDialogError(VpnDialog),
|
||||||
/// Update the list of known connections.
|
/// Update the list of known connections.
|
||||||
KnownConnections(IndexMap<UUID, ConnectionSettings>),
|
KnownConnections(IndexMap<UUID, ConnectionSettings>),
|
||||||
/// An update from the network manager daemon
|
/// An update from the network manager daemon
|
||||||
|
|
@ -169,6 +171,7 @@ enum VpnDialog {
|
||||||
username: String,
|
username: String,
|
||||||
password: SecureString,
|
password: SecureString,
|
||||||
password_hidden: bool,
|
password_hidden: bool,
|
||||||
|
error: Option<(ErrorKind, String)>,
|
||||||
},
|
},
|
||||||
RemoveProfile(ConnectionId),
|
RemoveProfile(ConnectionId),
|
||||||
WireGuardName(String, String, String),
|
WireGuardName(String, String, String),
|
||||||
|
|
@ -238,6 +241,7 @@ impl page::Page<crate::pages::Message> for Page {
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
password_hidden,
|
password_hidden,
|
||||||
|
error,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let username = widget::text_input(fl!("username"), username.as_str())
|
let username = widget::text_input(fl!("username"), username.as_str())
|
||||||
|
|
@ -251,11 +255,20 @@ impl page::Page<crate::pages::Message> for Page {
|
||||||
)
|
)
|
||||||
.on_input(|input| Message::PasswordUpdate(SecureString::from(input)))
|
.on_input(|input| Message::PasswordUpdate(SecureString::from(input)))
|
||||||
.on_submit(|_| Message::ConnectWithPassword);
|
.on_submit(|_| Message::ConnectWithPassword);
|
||||||
|
let (err_kind, error) = if let Some(err) = error.as_ref() {
|
||||||
|
(
|
||||||
|
Some(err.0),
|
||||||
|
Some(widget::text::body(err.1.as_str()).wrapping(Wrapping::Word)),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(None, None)
|
||||||
|
};
|
||||||
|
|
||||||
let controls = widget::column::with_capacity(2)
|
let controls = widget::column::with_capacity(2)
|
||||||
.spacing(12)
|
.spacing(12)
|
||||||
.push(username)
|
.push(username)
|
||||||
.push(password)
|
.push(password)
|
||||||
|
.push_maybe(error)
|
||||||
.apply(Element::from);
|
.apply(Element::from);
|
||||||
|
|
||||||
let primary_action = widget::button::suggested(fl!("connect"))
|
let primary_action = widget::button::suggested(fl!("connect"))
|
||||||
|
|
@ -265,7 +278,11 @@ impl page::Page<crate::pages::Message> for Page {
|
||||||
widget::button::standard(fl!("cancel")).on_press(Message::CancelDialog);
|
widget::button::standard(fl!("cancel")).on_press(Message::CancelDialog);
|
||||||
|
|
||||||
widget::dialog()
|
widget::dialog()
|
||||||
.title(fl!("auth-dialog"))
|
.title(if let Some(error_kind) = err_kind {
|
||||||
|
error_kind.localized()
|
||||||
|
} else {
|
||||||
|
fl!("auth-dialog")
|
||||||
|
})
|
||||||
.icon(icon::from_name("network-vpn-symbolic").size(64))
|
.icon(icon::from_name("network-vpn-symbolic").size(64))
|
||||||
.body(fl!("auth-dialog", "vpn-description"))
|
.body(fl!("auth-dialog", "vpn-description"))
|
||||||
.control(controls)
|
.control(controls)
|
||||||
|
|
@ -488,17 +505,26 @@ impl Page {
|
||||||
username: settings.username.clone().unwrap_or_default(),
|
username: settings.username.clone().unwrap_or_default(),
|
||||||
password: SecureString::from(""),
|
password: SecureString::from(""),
|
||||||
password_hidden: true,
|
password_hidden: true,
|
||||||
|
error: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
let connection_name = settings.id.clone();
|
let connection_name = settings.id.clone();
|
||||||
|
let username = settings.username.clone();
|
||||||
return cosmic::task::future(async move {
|
return cosmic::task::future(async move {
|
||||||
if let Err(why) = nmcli::connect(&connection_name).await {
|
if let Err(why) = nmcli::connect(&connection_name).await {
|
||||||
return Message::Error(
|
return Message::VpnDialogError(VpnDialog::Password {
|
||||||
ErrorKind::Connect,
|
error: Some((
|
||||||
format!("failed to connect to VPN: {why}"),
|
ErrorKind::Connect,
|
||||||
);
|
format!("failed to connect to VPN: {why}"),
|
||||||
|
)),
|
||||||
|
id: connection_name.clone(),
|
||||||
|
uuid,
|
||||||
|
username: username.clone().unwrap_or_default(),
|
||||||
|
password: SecureString::from(""),
|
||||||
|
password_hidden: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::Refresh
|
Message::Refresh
|
||||||
|
|
@ -534,7 +560,6 @@ impl Page {
|
||||||
self.close_popup_and_apply_updates();
|
self.close_popup_and_apply_updates();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::Settings(uuid) => {
|
Message::Settings(uuid) => {
|
||||||
self.close_popup_and_apply_updates();
|
self.close_popup_and_apply_updates();
|
||||||
|
|
||||||
|
|
@ -578,13 +603,14 @@ impl Page {
|
||||||
|
|
||||||
if let VpnDialog::Password {
|
if let VpnDialog::Password {
|
||||||
id,
|
id,
|
||||||
|
uuid,
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
..
|
..
|
||||||
} = dialog
|
} = dialog
|
||||||
{
|
{
|
||||||
return self
|
return self
|
||||||
.activate_with_password(id, username, password)
|
.activate_with_password(id, uuid, username, password)
|
||||||
.map(crate::app::Message::from);
|
.map(crate::app::Message::from);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -597,11 +623,9 @@ impl Page {
|
||||||
*username = user;
|
*username = user;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::CancelDialog => {
|
Message::CancelDialog => {
|
||||||
self.dialog = None;
|
self.dialog = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::TogglePasswordVisibility => {
|
Message::TogglePasswordVisibility => {
|
||||||
if let Some(VpnDialog::Password {
|
if let Some(VpnDialog::Password {
|
||||||
ref mut password_hidden,
|
ref mut password_hidden,
|
||||||
|
|
@ -620,6 +644,10 @@ impl Page {
|
||||||
Message::NetworkManagerConnect(conn) => {
|
Message::NetworkManagerConnect(conn) => {
|
||||||
return self.connect(conn.clone());
|
return self.connect(conn.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Message::VpnDialogError(vpn_dialog) => {
|
||||||
|
self.dialog = Some(vpn_dialog);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Task::none()
|
Task::none()
|
||||||
|
|
@ -628,24 +656,64 @@ impl Page {
|
||||||
fn activate_with_password(
|
fn activate_with_password(
|
||||||
&mut self,
|
&mut self,
|
||||||
connection_name: String,
|
connection_name: String,
|
||||||
|
uuid: Arc<str>,
|
||||||
username: String,
|
username: String,
|
||||||
password: SecureString,
|
password: SecureString,
|
||||||
) -> Task<Message> {
|
) -> Task<Message> {
|
||||||
cosmic::task::future(async move {
|
cosmic::task::future(async move {
|
||||||
if let Err(why) = nmcli::set_username(&connection_name, &username).await {
|
if let Err(why) = nmcli::set_username(&connection_name, &username).await {
|
||||||
return Message::Error(ErrorKind::WithPassword("username"), why.to_string());
|
return Message::VpnDialogError(VpnDialog::Password {
|
||||||
|
error: Some((ErrorKind::WithPassword("username"), why.to_string())),
|
||||||
|
id: connection_name.clone(),
|
||||||
|
uuid,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
password_hidden: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(why) = nmcli::set_password_flags_none(&connection_name).await {
|
if let Err(why) = nmcli::set_password_flags_none(&connection_name).await {
|
||||||
return Message::Error(ErrorKind::WithPassword("password-flags"), why.to_string());
|
return Message::VpnDialogError(VpnDialog::Password {
|
||||||
|
error: Some((ErrorKind::WithPassword("password-flags"), why.to_string())),
|
||||||
|
id: connection_name.clone(),
|
||||||
|
uuid,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
password_hidden: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(why) = nmcli::set_password_flags_none(&connection_name).await {
|
||||||
|
return Message::VpnDialogError(VpnDialog::Password {
|
||||||
|
error: Some((ErrorKind::WithPassword("password-flags"), why.to_string())),
|
||||||
|
id: connection_name.clone(),
|
||||||
|
uuid,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
password_hidden: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(why) = nmcli::set_password(&connection_name, password.unsecure()).await {
|
if let Err(why) = nmcli::set_password(&connection_name, password.unsecure()).await {
|
||||||
return Message::Error(ErrorKind::WithPassword("password"), why.to_string());
|
return Message::VpnDialogError(VpnDialog::Password {
|
||||||
|
error: Some((ErrorKind::WithPassword("password"), why.to_string())),
|
||||||
|
id: connection_name.clone(),
|
||||||
|
uuid,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
password_hidden: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(why) = nmcli::connect(&connection_name).await {
|
if let Err(why) = nmcli::connect(&connection_name).await {
|
||||||
return Message::Error(ErrorKind::Connect, why.to_string());
|
return Message::VpnDialogError(VpnDialog::Password {
|
||||||
|
error: Some((ErrorKind::Connect, why.to_string())),
|
||||||
|
id: connection_name.clone(),
|
||||||
|
uuid,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
password_hidden: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::Refresh
|
Message::Refresh
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue