use anyhow::{Context, Result};
#[allow(dead_code)]
pub fn resolve_password(
direct: Option<&str>,
file_path: Option<&str>,
env_var: Option<&str>,
field_name: &str,
) -> Result<String> {
if let Some(pwd) = direct {
return Ok(pwd.to_string());
}
if let Some(path) = file_path {
let content = std::fs::read_to_string(path)
.with_context(|| format!("Failed to read {field_name} from file: {path}"))?;
return Ok(content.trim().to_string());
}
if let Some(var_name) = env_var {
let value = std::env::var(var_name).with_context(|| {
format!("Environment variable '{var_name}' not set for {field_name}")
})?;
return Ok(value);
}
anyhow::bail!("{field_name} is required. Use --password, --password-file, or --password-env")
}
#[allow(dead_code)]
pub fn resolve_optional_password(
direct: Option<&str>,
file_path: Option<&str>,
env_var: Option<&str>,
field_name: &str,
) -> Result<Option<String>> {
if direct.is_none() && file_path.is_none() && env_var.is_none() {
return Ok(None);
}
resolve_password(direct, file_path, env_var, field_name).map(Some)
}
#[cfg(test)]
#[allow(unsafe_code)] mod tests {
use super::*;
use std::io::Write;
#[test]
fn test_resolve_direct_password() {
let result = resolve_password(Some("secret"), None, None, "test");
assert_eq!(result.unwrap(), "secret");
}
#[test]
fn test_resolve_password_file() {
let mut temp = tempfile::NamedTempFile::new().unwrap();
writeln!(temp, "file_secret").unwrap();
let result = resolve_password(None, Some(temp.path().to_str().unwrap()), None, "test");
assert_eq!(result.unwrap(), "file_secret");
}
#[test]
fn test_resolve_password_env() {
unsafe {
std::env::set_var("TEST_PASSWORD_12345", "env_secret");
}
let result = resolve_password(None, None, Some("TEST_PASSWORD_12345"), "test");
assert_eq!(result.unwrap(), "env_secret");
unsafe {
std::env::remove_var("TEST_PASSWORD_12345");
}
}
#[test]
fn test_resolve_password_priority() {
let mut temp = tempfile::NamedTempFile::new().unwrap();
writeln!(temp, "file_secret").unwrap();
let result = resolve_password(
Some("direct"),
Some(temp.path().to_str().unwrap()),
None,
"test",
);
assert_eq!(result.unwrap(), "direct");
}
#[test]
fn test_resolve_password_missing() {
let result = resolve_password(None, None, None, "certificate password");
assert!(result.is_err());
assert!(
result
.unwrap_err()
.to_string()
.contains("certificate password")
);
}
#[test]
fn test_resolve_optional_password_none() {
let result = resolve_optional_password(None, None, None, "test");
assert!(result.unwrap().is_none());
}
#[test]
fn test_resolve_optional_password_some() {
let result = resolve_optional_password(Some("secret"), None, None, "test");
assert_eq!(result.unwrap(), Some("secret".to_string()));
}
}