From 33a51bc6635427027a9672fb221de6702bc6d8e7 Mon Sep 17 00:00:00 2001 From: Aiden McClelland Date: Tue, 24 Feb 2026 16:06:19 -0700 Subject: [PATCH] setup changes --- core/locales/i18n.yaml | 7 +++ core/src/backup/restore.rs | 16 ++++--- core/src/hostname.rs | 27 +++++++++-- core/src/setup.rs | 47 ++++++++++++------- sdk/base/lib/osBindings/SetupExecuteParams.ts | 2 +- 5 files changed, 70 insertions(+), 29 deletions(-) diff --git a/core/locales/i18n.yaml b/core/locales/i18n.yaml index a8c08f73e..2a7d43343 100644 --- a/core/locales/i18n.yaml +++ b/core/locales/i18n.yaml @@ -197,6 +197,13 @@ setup.transferring-data: fr_FR: "Transfert de données" pl_PL: "Przesyłanie danych" +setup.password-required: + en_US: "Password is required for fresh setup" + de_DE: "Passwort ist für die Ersteinrichtung erforderlich" + es_ES: "Se requiere contraseña para la configuración inicial" + fr_FR: "Le mot de passe est requis pour la première configuration" + pl_PL: "Hasło jest wymagane do nowej konfiguracji" + # system.rs system.governor-not-available: en_US: "Governor %{governor} not available" diff --git a/core/src/backup/restore.rs b/core/src/backup/restore.rs index 2defc2d80..bc96d8823 100644 --- a/core/src/backup/restore.rs +++ b/core/src/backup/restore.rs @@ -86,7 +86,7 @@ pub async fn restore_packages_rpc( pub async fn recover_full_server( ctx: &SetupContext, disk_guid: InternedString, - password: String, + password: Option, recovery_source: TmpMountGuard, server_id: &str, recovery_password: &str, @@ -110,12 +110,14 @@ pub async fn recover_full_server( .with_ctx(|_| (ErrorKind::Filesystem, os_backup_path.display().to_string()))?, )?; - os_backup.account.password = argon2::hash_encoded( - password.as_bytes(), - &rand::random::<[u8; 16]>()[..], - &argon2::Config::rfc9106_low_mem(), - ) - .with_kind(ErrorKind::PasswordHashGeneration)?; + if let Some(password) = password { + os_backup.account.password = argon2::hash_encoded( + password.as_bytes(), + &rand::random::<[u8; 16]>()[..], + &argon2::Config::rfc9106_low_mem(), + ) + .with_kind(ErrorKind::PasswordHashGeneration)?; + } if let Some(h) = hostname { os_backup.account.hostname = h; diff --git a/core/src/hostname.rs b/core/src/hostname.rs index 4eaae7e51..0113afe75 100644 --- a/core/src/hostname.rs +++ b/core/src/hostname.rs @@ -251,18 +251,35 @@ pub async fn set_hostname_rpc( ctx: RpcContext, SetServerHostnameParams { name, hostname }: SetServerHostnameParams, ) -> Result<(), Error> { - let Some(hostname) = ServerHostnameInfo::new_opt(name, hostname)? else { + let name = name.filter(|n| !n.is_empty()); + let hostname = hostname + .filter(|h| !h.is_empty()) + .map(ServerHostname::new) + .transpose()?; + if name.is_none() && hostname.is_none() { return Err(Error::new( eyre!("{}", t!("hostname.must-provide-name-or-hostname")), ErrorKind::InvalidRequest, )); }; - ctx.db - .mutate(|db| hostname.save(db.as_public_mut().as_server_info_mut())) + let info = ctx + .db + .mutate(|db| { + let server_info = db.as_public_mut().as_server_info_mut(); + if let Some(name) = name { + server_info.as_name_mut().ser(&name)?; + } + if let Some(hostname) = &hostname { + hostname.save(server_info)?; + } + ServerHostnameInfo::load(server_info) + }) .await .result?; - ctx.account.mutate(|a| a.hostname = hostname.clone()); - sync_hostname(&hostname.hostname).await?; + ctx.account.mutate(|a| a.hostname = info.clone()); + if let Some(h) = hostname { + sync_hostname(&h).await?; + } Ok(()) } diff --git a/core/src/setup.rs b/core/src/setup.rs index 9ffdb8377..7e2764f3a 100644 --- a/core/src/setup.rs +++ b/core/src/setup.rs @@ -414,7 +414,7 @@ pub async fn setup_data_drive( #[ts(export)] pub struct SetupExecuteParams { guid: InternedString, - password: EncryptedWire, + password: Option, recovery_source: Option>, #[ts(optional)] kiosk: Option, @@ -434,15 +434,16 @@ pub async fn execute( hostname, }: SetupExecuteParams, ) -> Result { - let password = match password.decrypt(&ctx) { - Some(a) => a, - None => { - return Err(Error::new( - color_eyre::eyre::eyre!("{}", t!("setup.couldnt-decode-startos-password")), - crate::ErrorKind::Unknown, - )); - } - }; + let password = password + .map(|p| { + p.decrypt(&ctx).ok_or_else(|| { + Error::new( + color_eyre::eyre::eyre!("{}", t!("setup.couldnt-decode-startos-password")), + crate::ErrorKind::Unknown, + ) + }) + }) + .transpose()?; let recovery = match recovery_source { Some(RecoverySource::Backup { target, @@ -551,7 +552,7 @@ pub async fn shutdown(ctx: SetupContext) -> Result<(), Error> { pub async fn execute_inner( ctx: SetupContext, guid: InternedString, - password: String, + password: Option, recovery_source: Option>, kiosk: Option, hostname: Option, @@ -597,7 +598,22 @@ pub async fn execute_inner( Some(RecoverySource::Migrate { guid: old_guid }) => { migrate(&ctx, guid, &old_guid, password, kiosk, hostname, progress).await } - None => fresh_setup(&ctx, guid, &password, kiosk, hostname, progress).await, + None => { + fresh_setup( + &ctx, + guid, + &password.ok_or_else(|| { + Error::new( + eyre!("{}", t!("setup.password-required")), + ErrorKind::InvalidRequest, + ) + })?, + kiosk, + hostname, + progress, + ) + .await + } } } @@ -668,7 +684,7 @@ async fn fresh_setup( async fn recover( ctx: &SetupContext, guid: InternedString, - password: String, + password: Option, recovery_source: BackupTargetFS, server_id: String, recovery_password: String, @@ -696,7 +712,7 @@ async fn migrate( ctx: &SetupContext, guid: InternedString, old_guid: &str, - password: String, + password: Option, kiosk: Option, hostname: Option, SetupExecuteProgress { @@ -777,8 +793,7 @@ async fn migrate( crate::disk::main::export(&old_guid, "/media/startos/migrate").await?; restore_phase.complete(); - let (account, net_ctrl) = - setup_init(&ctx, Some(password), kiosk, hostname, init_phases).await?; + let (account, net_ctrl) = setup_init(&ctx, password, kiosk, hostname, init_phases).await?; let rpc_ctx = RpcContext::init( &ctx.webserver, diff --git a/sdk/base/lib/osBindings/SetupExecuteParams.ts b/sdk/base/lib/osBindings/SetupExecuteParams.ts index 4c3e41759..69f358c54 100644 --- a/sdk/base/lib/osBindings/SetupExecuteParams.ts +++ b/sdk/base/lib/osBindings/SetupExecuteParams.ts @@ -4,7 +4,7 @@ import type { RecoverySource } from './RecoverySource' export type SetupExecuteParams = { guid: string - password: EncryptedWire + password: EncryptedWire | null recoverySource: RecoverySource | null kiosk?: boolean name: string | null