From b6124537f93e9bed82c682a0b441543367004766 Mon Sep 17 00:00:00 2001 From: Ross Andrews Date: Thu, 14 May 2026 20:05:17 -0500 Subject: [PATCH] comments --- src/info_operation.rs | 4 ++-- src/open_operation.rs | 6 +++--- src/utils.rs | 13 ++++++++++++- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/info_operation.rs b/src/info_operation.rs index a62b97d..9e641e2 100644 --- a/src/info_operation.rs +++ b/src/info_operation.rs @@ -17,7 +17,7 @@ enum ArchiveInfo { } fn archive_info(data: &[u8]) -> Result { - let mut archive = open_archive(data); + let mut archive = archive_reader_for(data); let mut entries = archive.entries().map_err(|_| DrawerError::UntarFailed)?; let first = entries.next() @@ -31,7 +31,7 @@ fn archive_info(data: &[u8]) -> Result { } } - let mut archive = open_archive(data); + let mut archive = archive_reader_for(data); let file_count = archive.entries() .map_err(|_| DrawerError::UntarFailed)? .filter_map(|e| e.ok()) diff --git a/src/open_operation.rs b/src/open_operation.rs index 97a35d1..a046701 100644 --- a/src/open_operation.rs +++ b/src/open_operation.rs @@ -15,7 +15,7 @@ pub struct OpenOperation { } fn single_file_entry(data: &[u8]) -> Option { - let mut archive = open_archive(data); + let mut archive = archive_reader_for(data); let mut entries = archive.entries().ok()?; let entry = entries.next()?.ok()?; if !entry.header().entry_type().is_file() { @@ -28,7 +28,7 @@ fn single_file_entry(data: &[u8]) -> Option { } fn unpack_single_file(data: &[u8], target: &Path) -> Result<(), DrawerError> { - let mut archive = open_archive(data); + let mut archive = archive_reader_for(data); let mut entry = archive.entries() .map_err(|_| DrawerError::UntarFailed)? .next() @@ -39,7 +39,7 @@ fn unpack_single_file(data: &[u8], target: &Path) -> Result<(), DrawerError> { } fn unpack_directory(data: &[u8], target: &Path) -> Result<(), DrawerError> { - let mut archive = open_archive(data); + let mut archive = archive_reader_for(data); archive.unpack(target).map_err(|_| DrawerError::UntarFailed)?; Ok(()) } diff --git a/src/utils.rs b/src/utils.rs index 6f78bf9..62542b9 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -4,6 +4,7 @@ use age::ssh::Identity; use flate2::read::GzDecoder; use crate::error::DrawerError; +/// Returns the parent directory of `p`, or `"."` if `p` has no parent or an empty parent. pub fn parent_or_dot(p: &Path) -> &Path { match p.parent() { None => Path::new("."), @@ -12,10 +13,12 @@ pub fn parent_or_dot(p: &Path) -> &Path { } } -pub fn open_archive(data: &[u8]) -> tar::Archive>> { +/// Wraps `data` in a gzip-decompressing tar archive reader. +pub fn archive_reader_for(data: &[u8]) -> tar::Archive>> { tar::Archive::new(GzDecoder::new(std::io::Cursor::new(data))) } +/// Resolves the key path from the explicit `-i` argument or the `$DRAWER_KEY` environment variable. pub fn key_path(key: &Option) -> Result { if let Some(k) = key { return Ok(k.clone()); @@ -24,6 +27,7 @@ pub fn key_path(key: &Option) -> Result { Ok(PathBuf::from(val)) } +/// Loads the SSH identity from disk, returning both the resolved key path and the parsed identity. pub fn identity(key: &Option, drawer_file: &Path) -> Result<(PathBuf, Identity), DrawerError> { let kp = key_path(key)?; let file = std::fs::File::open(&kp) @@ -34,6 +38,7 @@ pub fn identity(key: &Option, drawer_file: &Path) -> Result<(PathBuf, I Ok((kp, id)) } +/// Decrypts `encrypted` using the SSH key, returning the plaintext bytes. pub fn decrypt(encrypted: Vec, key: &Option, drawer_file: &Path) -> Result, DrawerError> { let (kp, id) = identity(key, drawer_file)?; let decryptor = age::Decryptor::new(encrypted.as_slice()) @@ -46,6 +51,7 @@ pub fn decrypt(encrypted: Vec, key: &Option, drawer_file: &Path) -> Ok(decrypted) } +/// Encrypts `buf` to the SSH public key derived from the identity, returning the ciphertext. pub fn encrypt(buf: &[u8], key: &Option, drawer_file: &Path) -> Result, DrawerError> { let (_, id) = identity(key, drawer_file)?; let recipient = age::ssh::Recipient::try_from(id) @@ -61,6 +67,8 @@ pub fn encrypt(buf: &[u8], key: &Option, drawer_file: &Path) -> Result< Ok(encrypted) } +/// Returns the default open/close target path: the single file's name for single-file archives, +/// or the drawer file's stem for directory archives. pub fn default_target(drawer_file: &Path, single_file: Option<&Path>) -> PathBuf { match single_file { Some(p) => PathBuf::from(p.file_name().unwrap_or_default()), @@ -68,6 +76,7 @@ pub fn default_target(drawer_file: &Path, single_file: Option<&Path>) -> PathBuf } } +/// Errors if `drawer_file` does not have the `.drawer` extension. pub fn validate_drawer_extension(drawer_file: &Path) -> Result<(), DrawerError> { if drawer_file.extension().and_then(|e| e.to_str()) != Some("drawer") { return Err(DrawerError::DrawerFileInvalidExtension(drawer_file.to_path_buf())); @@ -75,6 +84,7 @@ pub fn validate_drawer_extension(drawer_file: &Path) -> Result<(), DrawerError> Ok(()) } +/// Errors if `drawer_file` does not exist on disk. pub fn validate_drawer_file_exists(drawer_file: &Path) -> Result<(), DrawerError> { if !drawer_file.exists() { return Err(DrawerError::DrawerFileNotFound(drawer_file.to_path_buf())); @@ -82,6 +92,7 @@ pub fn validate_drawer_file_exists(drawer_file: &Path) -> Result<(), DrawerError Ok(()) } +/// Errors if the key cannot be loaded as a valid SSH identity usable for age encryption. pub fn validate_ssh_key(key: &Option) -> Result<(), DrawerError> { let kp = key_path(key)?; let file = std::fs::File::open(&kp)