comments
This commit is contained in:
@@ -17,7 +17,7 @@ enum ArchiveInfo {
|
||||
}
|
||||
|
||||
fn archive_info(data: &[u8]) -> Result<ArchiveInfo, DrawerError> {
|
||||
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<ArchiveInfo, DrawerError> {
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
|
||||
@@ -15,7 +15,7 @@ pub struct OpenOperation {
|
||||
}
|
||||
|
||||
fn single_file_entry(data: &[u8]) -> Option<PathBuf> {
|
||||
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<PathBuf> {
|
||||
}
|
||||
|
||||
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(())
|
||||
}
|
||||
|
||||
+12
-1
@@ -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<GzDecoder<std::io::Cursor<&[u8]>>> {
|
||||
/// Wraps `data` in a gzip-decompressing tar archive reader.
|
||||
pub fn archive_reader_for(data: &[u8]) -> tar::Archive<GzDecoder<std::io::Cursor<&[u8]>>> {
|
||||
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<PathBuf>) -> Result<PathBuf, DrawerError> {
|
||||
if let Some(k) = key {
|
||||
return Ok(k.clone());
|
||||
@@ -24,6 +27,7 @@ pub fn key_path(key: &Option<PathBuf>) -> Result<PathBuf, DrawerError> {
|
||||
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<PathBuf>, 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<PathBuf>, drawer_file: &Path) -> Result<(PathBuf, I
|
||||
Ok((kp, id))
|
||||
}
|
||||
|
||||
/// Decrypts `encrypted` using the SSH key, returning the plaintext bytes.
|
||||
pub fn decrypt(encrypted: Vec<u8>, key: &Option<PathBuf>, drawer_file: &Path) -> Result<Vec<u8>, 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<u8>, key: &Option<PathBuf>, 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<PathBuf>, drawer_file: &Path) -> Result<Vec<u8>, 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<PathBuf>, 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<PathBuf>) -> Result<(), DrawerError> {
|
||||
let kp = key_path(key)?;
|
||||
let file = std::fs::File::open(&kp)
|
||||
|
||||
Reference in New Issue
Block a user