//! Used for resolving autodetects use super::*; use std::{ path::{ Path, }, error, fmt, io, }; use tokio::{ prelude::*, fs::{ OpenOptions, File, }, io::{ BufReader, }, }; use config::op::KeyFormat; /// Find the format (Binary, Text, PEM) of this key file. /// /// # Note /// This isn't an infallible test as it only parses parts of headers, if it detects a type it doesn't guarantee that the file *actually* is that type. It is just a hint or best-guess. #[instrument(err, skip(path), fields(path = ?path.as_ref()))] pub async fn find_key_format(path: impl AsRef, can_pem: bool) -> eyre::Result { async fn check_bin(file: &mut File) -> Result { let mut buffer = [0u8; 4]; file.read_exact(&mut buffer[..]).await?; Ok(&buffer[..] == format::RAE_HEADER_BIT) } async fn check_text(file: &mut File) -> Result { let mut buffer = [0u8; 4]; file.read_exact(&mut buffer[..]).await?; if &buffer[..] != b"--- " { return Ok(false); } file.read_exact(&mut buffer[..]).await?; Ok(&buffer[..] == format::RAE_HEADER_BIT) } async fn check_pem(file: &mut File) -> Result { todo!("I don't remember the PEM format right now") } let mut file = { let path = path.as_ref(); OpenOptions::new() .read(true) .open(path).await .wrap_err(eyre::eyre!("Failed to open file to check")) .with_section(|| format!("{:?}", path).header("Path was"))? }; macro_rules! reset { () => { file.seek(std::io::SeekFrom::Start(0)).await? } } if can_pem { if check_pem(&mut file).await .with_note(|| "With check for PEM")? { return Ok(KeyFormat::PEM); } else { reset!(); } } if check_bin(&mut file).await .with_note(|| "With check for binary")? { return Ok(KeyFormat::Bin); } else { reset!(); } if check_text(&mut file).await .with_note(|| "With check for text")? { return Ok(KeyFormat::Text); } return Err(Error::UnknownFormat)?; } pub async fn find_file_mode>(path: P) -> Result { //TODO: we need to calculate mode here todo!() } pub async fn find_key_mode>(path: P) -> Result { //TODO: we need to calculate mode here todo!() } #[derive(Debug)] #[non_exhaustive] pub enum Error { UnknownFormat, IO(io::Error), Unknown, } impl error::Error for Error{} impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { _ => write!(f, "unknown error"), } } } impl From for Error { #[inline] fn from(from: io::Error) -> Self { Self::IO(from) } }