use ai_model_vault::{kms, Result, Vault, VaultBuilder, VaultConfig};
use std::io::{self, BufRead, IsTerminal, Write};
use zeroize::Zeroize;
pub const PASSPHRASE_ENV: &str = "aimodelvault_PASSPHRASE";
pub fn prompt_passphrase(prompt: &str) -> Result<Vec<u8>> {
if let Ok(mut value) = std::env::var(PASSPHRASE_ENV) {
if !value.is_empty() {
let resolved = kms::resolve(&value);
value.zeroize();
let mut resolved = resolved?;
let bytes = resolved.as_bytes().to_vec();
resolved.zeroize();
return Ok(bytes);
}
}
let stdin = io::stdin();
if !stdin.is_terminal() {
let mut line = String::new();
let read = stdin.lock().read_line(&mut line);
match read {
Ok(n) if n > 0 => {
let trimmed = line.trim_end_matches(['\n', '\r']);
if !trimmed.is_empty() {
let bytes = trimmed.as_bytes().to_vec();
line.zeroize();
return Ok(bytes);
}
line.zeroize();
}
Ok(_) => line.zeroize(),
Err(err) => {
line.zeroize();
return Err(err.into());
}
}
}
print!("{}", prompt);
io::stdout().flush()?;
let passphrase = rpassword::read_password()?;
if passphrase.is_empty() {
return Err(ai_model_vault::VaultError::InvalidInput(format!(
"No passphrase provided. Set ${PASSPHRASE_ENV} (a literal value or a \
KMS URI), pipe it on stdin, or run interactively."
)));
}
Ok(passphrase.into_bytes())
}
pub fn build_vault(config: VaultConfig, use_sqlite: bool) -> Result<Vault> {
let mut builder = VaultBuilder::new().config(config);
if use_sqlite {
#[cfg(feature = "sqlite")]
{
builder = builder.sqlite_versions();
}
#[cfg(not(feature = "sqlite"))]
{
return Err(ai_model_vault::VaultError::ConfigError(
"SQLite version backend requires the `sqlite` feature".to_string(),
));
}
}
builder.build()
}