From f3bf015c49d057d4c80a303d043816cd9e5962ba Mon Sep 17 00:00:00 2001 From: Josef Reidinger Date: Tue, 1 Apr 2025 13:07:01 +0200 Subject: [PATCH 1/3] do not export empty defaults for user --- rust/agama-lib/src/users/settings.rs | 4 ++++ rust/agama-lib/src/users/store.rs | 16 +++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/rust/agama-lib/src/users/settings.rs b/rust/agama-lib/src/users/settings.rs index 5aa359958a..53729c2d5a 100644 --- a/rust/agama-lib/src/users/settings.rs +++ b/rust/agama-lib/src/users/settings.rs @@ -38,12 +38,16 @@ 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 = "Option::is_none")] pub hashed_password: Option, } diff --git a/rust/agama-lib/src/users/store.rs b/rust/agama-lib/src/users/store.rs index 5235a4b66e..ab69613afe 100644 --- a/rust/agama-lib/src/users/store.rs +++ b/rust/agama-lib/src/users/store.rs @@ -40,12 +40,22 @@ impl UsersStore { }) } + // small helper to convert dbus empty string to None + fn optional_string(value: String) -> Option { + if value.is_empty() { + None + } else { + Some(value) + } + } + 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: Self::optional_string(first_user.user_name), + full_name: Self::optional_string(first_user.full_name), + password: Self::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 root_user = self.users_client.root_user().await?; From 05f476c21838130d3710d0a0ff0fc90ce5081d90 Mon Sep 17 00:00:00 2001 From: Josef Reidinger Date: Tue, 1 Apr 2025 19:16:47 +0200 Subject: [PATCH 2/3] improve users export even more to skip not set values. --- rust/agama-lib/src/users/settings.rs | 29 ++++++++++++++++++++++++++-- rust/agama-lib/src/users/store.rs | 14 ++++++++++++-- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/rust/agama-lib/src/users/settings.rs b/rust/agama-lib/src/users/settings.rs index 53729c2d5a..8bc9168199 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, } @@ -47,10 +48,25 @@ pub struct FirstUserSettings { #[serde(skip_serializing_if = "Option::is_none")] pub password: Option, /// Whether the password is hashed or is plain text - #[serde(skip_serializing_if = "Option::is_none")] + #[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. @@ -67,3 +83,12 @@ 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() + } +} \ No newline at end of file diff --git a/rust/agama-lib/src/users/store.rs b/rust/agama-lib/src/users/store.rs index ab69613afe..772686d410 100644 --- a/rust/agama-lib/src/users/store.rs +++ b/rust/agama-lib/src/users/store.rs @@ -58,16 +58,26 @@ impl UsersStore { // 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, }) } From 4474a9c29e12ca6f13078c3f708d060d59765f5e Mon Sep 17 00:00:00 2001 From: Josef Reidinger Date: Tue, 1 Apr 2025 19:20:19 +0200 Subject: [PATCH 3/3] format and move helper --- rust/agama-lib/src/dbus.rs | 9 +++++++++ rust/agama-lib/src/users/settings.rs | 7 ++----- rust/agama-lib/src/users/store.rs | 28 ++++++++++------------------ 3 files changed, 21 insertions(+), 23 deletions(-) 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 8bc9168199..4eba6914cb 100644 --- a/rust/agama-lib/src/users/settings.rs +++ b/rust/agama-lib/src/users/settings.rs @@ -84,11 +84,8 @@ pub struct RootUserSettings { 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() + self.password.is_none() && self.hashed_password.is_none() && self.ssh_public_key.is_none() } -} \ No newline at end of file +} diff --git a/rust/agama-lib/src/users/store.rs b/rust/agama-lib/src/users/store.rs index 772686d410..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. @@ -40,29 +41,20 @@ impl UsersStore { }) } - // small helper to convert dbus empty string to None - fn optional_string(value: String) -> Option { - if value.is_empty() { - None - } else { - Some(value) - } - } - pub async fn load(&self) -> Result { let first_user = self.users_client.first_user().await?; let first_user = FirstUserSettings { - user_name: Self::optional_string(first_user.user_name), - full_name: Self::optional_string(first_user.full_name), - password: Self::optional_string(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) - }; + } else { + Some(first_user) + }; let root_user = self.users_client.root_user().await?; let root_user = RootUserSettings { password: root_user.password, @@ -71,9 +63,9 @@ impl UsersStore { }; let root_user = if root_user.skip_export() { None - } else { - Some(root_user) - }; + } else { + Some(root_user) + }; Ok(UserSettings { first_user: first_user,