use super::config::AuthConfig;
use super::config::AuthMode;
impl AuthConfig {
pub fn resolve_superuser_password(
&self,
data_dir: &std::path::Path,
) -> crate::Result<Option<String>> {
if self.mode == AuthMode::Trust {
return Ok(None);
}
if let Ok(env_pw) = std::env::var("NODEDB_SUPERUSER_PASSWORD")
&& !env_pw.is_empty()
{
return Ok(Some(env_pw));
}
if let Some(ref pw) = self.superuser_password
&& !pw.is_empty()
{
return Ok(Some(pw.clone()));
}
let pw_path = data_dir.join(".superuser_password");
if let Ok(existing) = std::fs::read_to_string(&pw_path) {
let trimmed = existing.trim().to_string();
if !trimmed.is_empty() {
return Ok(Some(trimmed));
}
}
let generated = generate_superuser_password();
if let Some(parent) = pw_path.parent() {
std::fs::create_dir_all(parent).map_err(|e| crate::Error::Config {
detail: format!("failed to create data dir {parent:?}: {e}"),
})?;
}
std::fs::write(&pw_path, &generated).map_err(|e| crate::Error::Config {
detail: format!("failed to persist superuser password to {pw_path:?}: {e}"),
})?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let _ = std::fs::set_permissions(&pw_path, std::fs::Permissions::from_mode(0o600));
}
eprintln!();
eprintln!(" ╔══════════════════════════════════════════════════════════════╗");
eprintln!(" ║ AUTO-GENERATED SUPERUSER PASSWORD (FIRST RUN) ║");
eprintln!(" ╠══════════════════════════════════════════════════════════════╣");
eprintln!(" ║ user: {:<50}║", self.superuser_name);
eprintln!(" ║ password: {generated:<50}║");
eprintln!(" ║ saved to: {:<50}║", pw_path.display().to_string());
eprintln!(" ║ ║");
eprintln!(" ║ Override via NODEDB_SUPERUSER_PASSWORD or auth config. ║");
eprintln!(" ╚══════════════════════════════════════════════════════════════╝");
eprintln!();
Ok(Some(generated))
}
}
fn generate_superuser_password() -> String {
use rand::Rng;
const ALPHABET: &[u8] = b"abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789";
let mut rng = rand::rng();
(0..24)
.map(|_| ALPHABET[rng.random_range(0..ALPHABET.len())] as char)
.collect()
}