diff --git a/crates/musicus/src/preferences/login.rs b/crates/musicus/src/preferences/login.rs index 27551c9..2df4038 100644 --- a/crates/musicus/src/preferences/login.rs +++ b/crates/musicus/src/preferences/login.rs @@ -10,15 +10,15 @@ use std::rc::Rc; /// A dialog for entering login credentials. pub struct LoginDialog { - handle: NavigationHandle, + handle: NavigationHandle>, widget: gtk::Stack, info_bar: gtk::InfoBar, username_entry: gtk::Entry, password_entry: gtk::Entry, } -impl Screen<(), LoginData> for LoginDialog { - fn new(_: (), handle: NavigationHandle) -> Rc { +impl Screen, Option> for LoginDialog { + fn new(data: Option, handle: NavigationHandle>) -> Rc { // Create UI let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/login_dialog.ui"); @@ -28,7 +28,16 @@ impl Screen<(), LoginData> for LoginDialog { get_widget!(builder, gtk::Button, login_button); get_widget!(builder, gtk::Entry, username_entry); get_widget!(builder, gtk::Entry, password_entry); + get_widget!(builder, gtk::Box, register_box); get_widget!(builder, gtk::Button, register_button); + get_widget!(builder, gtk::Box, logout_box); + get_widget!(builder, gtk::Button, logout_button); + + if let Some(data) = data { + username_entry.set_text(&data.username); + register_box.hide(); + logout_box.show(); + } let this = Rc::new(Self { handle, @@ -53,9 +62,9 @@ impl Screen<(), LoginData> for LoginDialog { }; spawn!(@clone this, async move { - this.handle.backend.set_login_data(data.clone()).await; + this.handle.backend.set_login_data(Some(data.clone())).await; if this.handle.backend.cl().login().await.unwrap() { - this.handle.pop(Some(data)); + this.handle.pop(Some(Some(data))); } else { this.widget.set_visible_child_name("content"); this.info_bar.set_revealed(true); @@ -66,11 +75,18 @@ impl Screen<(), LoginData> for LoginDialog { register_button.connect_clicked(clone!(@weak this => move |_| { spawn!(@clone this, async move { if let Some(data) = push!(this.handle, RegisterDialog).await { - this.handle.pop(Some(data)); + this.handle.pop(Some(Some(data))); } }); })); + logout_button.connect_clicked(clone!(@weak this => move |_| { + spawn!(@clone this, async move { + this.handle.backend.set_login_data(None).await; + this.handle.pop(Some(None)); + }); + })); + this } } diff --git a/crates/musicus/src/preferences/mod.rs b/crates/musicus/src/preferences/mod.rs index 530b24d..761fdd8 100644 --- a/crates/musicus/src/preferences/mod.rs +++ b/crates/musicus/src/preferences/mod.rs @@ -96,8 +96,12 @@ impl Preferences { window.set_transient_for(&this.window); spawn!(@clone this, async move { - if let Some(data) = replace!(window.navigator, LoginDialog).await { - this.login_row.set_subtitle(Some(&data.username)); + if let Some(data) = replace!(window.navigator, LoginDialog, this.backend.get_login_data()).await { + if let Some(data) = data { + this.login_row.set_subtitle(Some(&data.username)); + } else { + this.login_row.set_subtitle(Some(&gettext("Not logged in"))); + } } }); })); diff --git a/crates/musicus_backend/src/lib.rs b/crates/musicus_backend/src/lib.rs index c21fc19..3c7dffc 100644 --- a/crates/musicus_backend/src/lib.rs +++ b/crates/musicus_backend/src/lib.rs @@ -98,7 +98,7 @@ impl Backend { } match Self::load_login_data().await { - Ok(Some(data)) => self.client.set_login_data(data), + Ok(Some(data)) => self.client.set_login_data(Some(data)), Err(err) => warn!("The login data could not be loaded from SecretService. It will not \ be available. Error message: {}", err), _ => (), @@ -129,11 +129,19 @@ impl Backend { } /// Set the user credentials to use. - pub async fn set_login_data(&self, data: LoginData) { - if let Err(err) = Self::store_login_data(data.clone()).await { - warn!("An error happened while trying to store the login data using SecretService. \ - This means, that they will not be available at the next startup most likely. \ - Error message: {}", err); + pub async fn set_login_data(&self, data: Option) { + if let Some(data) = &data { + if let Err(err) = Self::store_login_data(data.clone()).await { + warn!("An error happened while trying to store the login data using SecretService. \ + This means, that they will not be available at the next startup most likely. \ + Error message: {}", err); + } + } else { + if let Err(err) = Self::delete_secrets().await { + warn!("An error happened while trying to delete the login data from SecretService. \ + This may result in the login data being reloaded at the next startup. Error \ + message: {}", err); + } } self.client.set_login_data(data); diff --git a/crates/musicus_backend/src/secure.rs b/crates/musicus_backend/src/secure.rs index 2e42aee..7005a00 100644 --- a/crates/musicus_backend/src/secure.rs +++ b/crates/musicus_backend/src/secure.rs @@ -20,6 +20,13 @@ impl Backend { receiver.await? } + /// Delete all stored secrets. + pub(super) async fn delete_secrets() -> Result<()> { + let (sender, receiver) = oneshot::channel(); + thread::spawn(move || sender.send(Self::delete_secrets_priv()).unwrap()); + receiver.await? + } + /// Get the login credentials from secret storage. fn load_login_data_priv() -> Result> { let ss = SecretService::new(EncryptionType::Dh)?; @@ -52,7 +59,7 @@ impl Backend { let collection = Self::get_collection(&ss)?; let key = "musicus-login-data"; - Self::delete_secrets(&collection, key)?; + Self::delete_secrets_for_key(&collection, key)?; let mut attributes = HashMap::new(); attributes.insert("username", data.username.as_str()); @@ -61,8 +68,19 @@ impl Backend { Ok(()) } + /// Delete all stored secrets. + fn delete_secrets_priv() -> Result<()> { + let ss = SecretService::new(EncryptionType::Dh)?; + let collection = Self::get_collection(&ss)?; + + let key = "musicus-login-data"; + Self::delete_secrets_for_key(&collection, key)?; + + Ok(()) + } + /// Delete all stored secrets for the provided key. - fn delete_secrets(collection: &Collection, key: &str) -> Result<()> { + fn delete_secrets_for_key(collection: &Collection, key: &str) -> Result<()> { let items = collection.get_all_items()?; for item in items { diff --git a/crates/musicus_client/src/lib.rs b/crates/musicus_client/src/lib.rs index acd6d45..c2fd58c 100644 --- a/crates/musicus_client/src/lib.rs +++ b/crates/musicus_client/src/lib.rs @@ -65,8 +65,8 @@ impl Client { } /// Set the user credentials to use. - pub fn set_login_data(&self, data: LoginData) { - self.login_data.replace(Some(data)); + pub fn set_login_data(&self, data: Option) { + self.login_data.replace(data); self.token.replace(None); } diff --git a/res/ui/login_dialog.ui b/res/ui/login_dialog.ui index 56508c4..9a468ac 100644 --- a/res/ui/login_dialog.ui +++ b/res/ui/login_dialog.ui @@ -100,29 +100,74 @@ - - start - Create a new account - - - + + vertical + 12 + + + start + Create a new account + + + + + + + + start + + + none + + + True + Register a new account + register_button + + + Start + center + + + + + + + + - - start + + vertical + 12 + false - - none + + start + Logout + + + + + + + + start - - True - Register a new account - register_button + + none - - Start - center + + True + Don't use an account + logout_button + + + Logout + center + +