diff --git a/rust/agama-lib/src/dbus.rs b/rust/agama-lib/src/dbus.rs index 78984d5625..ef5ca69346 100644 --- a/rust/agama-lib/src/dbus.rs +++ b/rust/agama-lib/src/dbus.rs @@ -101,6 +101,15 @@ pub fn extract_id_from_path(path: &OwnedObjectPath) -> Result Option { + if value.is_empty() { + None + } else { + Some(value) + } +} + #[cfg(test)] mod tests { use std::collections::HashMap; diff --git a/rust/agama-lib/src/users/settings.rs b/rust/agama-lib/src/users/settings.rs index 5aa359958a..4eba6914cb 100644 --- a/rust/agama-lib/src/users/settings.rs +++ b/rust/agama-lib/src/users/settings.rs @@ -26,8 +26,9 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Default, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct UserSettings { - #[serde(rename = "user")] + #[serde(rename = "user", skip_serializing_if = "Option::is_none")] pub first_user: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub root: Option, } @@ -38,15 +39,34 @@ pub struct UserSettings { #[serde(rename_all = "camelCase")] pub struct FirstUserSettings { /// First user's full name + #[serde(skip_serializing_if = "Option::is_none")] pub full_name: Option, /// First user's username + #[serde(skip_serializing_if = "Option::is_none")] pub user_name: Option, /// First user's password (in clear text) + #[serde(skip_serializing_if = "Option::is_none")] pub password: Option, /// Whether the password is hashed or is plain text + #[serde(skip_serializing_if = "Self::skip_hashed")] pub hashed_password: Option, } +impl FirstUserSettings { + // as dbus provides only boolean it is hard to distinguish + // false and not set. So act for false like not set as it is default. + fn skip_hashed(value: &Option) -> bool { + *value == Some(false) + } + + pub fn skip_export(&self) -> bool { + self.full_name.is_none() + && self.user_name.is_none() + && self.password.is_none() + && Self::skip_hashed(&self.hashed_password) + } +} + /// Root user settings /// /// Holds the settings for the root user. @@ -63,3 +83,9 @@ pub struct RootUserSettings { #[serde(skip_serializing_if = "Option::is_none")] pub ssh_public_key: Option, } + +impl RootUserSettings { + pub fn skip_export(&self) -> bool { + self.password.is_none() && self.hashed_password.is_none() && self.ssh_public_key.is_none() + } +} diff --git a/rust/agama-lib/src/users/store.rs b/rust/agama-lib/src/users/store.rs index 5235a4b66e..8637ba50ea 100644 --- a/rust/agama-lib/src/users/store.rs +++ b/rust/agama-lib/src/users/store.rs @@ -20,6 +20,7 @@ use super::{FirstUser, FirstUserSettings, RootUserSettings, UserSettings, UsersHTTPClient}; use crate::base_http_client::BaseHTTPClient; +use crate::dbus::optional_string; use crate::error::ServiceError; /// Loads and stores the users settings from/to the D-Bus service. @@ -43,21 +44,32 @@ impl UsersStore { pub async fn load(&self) -> Result { let first_user = self.users_client.first_user().await?; let first_user = FirstUserSettings { - user_name: Some(first_user.user_name), - full_name: Some(first_user.full_name), - password: Some(first_user.password), + user_name: optional_string(first_user.user_name), + full_name: optional_string(first_user.full_name), + password: optional_string(first_user.password), + // sadly for boolean we do not have on dbus way to set it to not_set hashed_password: Some(first_user.hashed_password), }; + let first_user = if first_user.skip_export() { + None + } else { + Some(first_user) + }; let root_user = self.users_client.root_user().await?; let root_user = RootUserSettings { password: root_user.password, hashed_password: root_user.hashed_password, ssh_public_key: root_user.ssh_public_key, }; + let root_user = if root_user.skip_export() { + None + } else { + Some(root_user) + }; Ok(UserSettings { - first_user: Some(first_user), - root: Some(root_user), + first_user: first_user, + root: root_user, }) }