use std::io::Read;
use std::path::Path;
use microvms_app::error::Error;
pub fn read_secret_file(path: &Path) -> Result<String, Error> {
let mut options = std::fs::OpenOptions::new();
options.read(true);
#[cfg(unix)]
{
use std::os::unix::fs::OpenOptionsExt;
options.custom_flags(libc::O_NONBLOCK);
}
let mut file = options.open(path).map_err(read_error)?;
let metadata = file.metadata().map_err(read_error)?;
if !metadata.is_file() {
return Err(Error::invalid_arg("secret input must name a regular file"));
}
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
if metadata.permissions().mode() & 0o077 != 0 {
return Err(Error::invalid_arg(
"secret file must grant no permissions to group or other users",
));
}
}
read_secret(&mut file)
}
pub fn read_secret(reader: &mut dyn Read) -> Result<String, Error> {
let mut value = String::new();
reader.read_to_string(&mut value).map_err(read_error)?;
let value = value.trim_end_matches(['\r', '\n']);
if value.is_empty() {
return Err(Error::invalid_arg("secret input must not be empty"));
}
Ok(value.to_owned())
}
fn read_error(error: std::io::Error) -> Error {
Error::invalid_arg(format!("could not read secret input: {error}"))
}