comments
This commit is contained in:
@@ -17,7 +17,7 @@ enum ArchiveInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn archive_info(data: &[u8]) -> Result<ArchiveInfo, DrawerError> {
|
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 mut entries = archive.entries().map_err(|_| DrawerError::UntarFailed)?;
|
||||||
|
|
||||||
let first = entries.next()
|
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()
|
let file_count = archive.entries()
|
||||||
.map_err(|_| DrawerError::UntarFailed)?
|
.map_err(|_| DrawerError::UntarFailed)?
|
||||||
.filter_map(|e| e.ok())
|
.filter_map(|e| e.ok())
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ pub struct OpenOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn single_file_entry(data: &[u8]) -> Option<PathBuf> {
|
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 mut entries = archive.entries().ok()?;
|
||||||
let entry = entries.next()?.ok()?;
|
let entry = entries.next()?.ok()?;
|
||||||
if !entry.header().entry_type().is_file() {
|
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> {
|
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()
|
let mut entry = archive.entries()
|
||||||
.map_err(|_| DrawerError::UntarFailed)?
|
.map_err(|_| DrawerError::UntarFailed)?
|
||||||
.next()
|
.next()
|
||||||
@@ -39,7 +39,7 @@ fn unpack_single_file(data: &[u8], target: &Path) -> Result<(), DrawerError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn unpack_directory(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)?;
|
archive.unpack(target).map_err(|_| DrawerError::UntarFailed)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-1
@@ -4,6 +4,7 @@ use age::ssh::Identity;
|
|||||||
use flate2::read::GzDecoder;
|
use flate2::read::GzDecoder;
|
||||||
use crate::error::DrawerError;
|
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 {
|
pub fn parent_or_dot(p: &Path) -> &Path {
|
||||||
match p.parent() {
|
match p.parent() {
|
||||||
None => Path::new("."),
|
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)))
|
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> {
|
pub fn key_path(key: &Option<PathBuf>) -> Result<PathBuf, DrawerError> {
|
||||||
if let Some(k) = key {
|
if let Some(k) = key {
|
||||||
return Ok(k.clone());
|
return Ok(k.clone());
|
||||||
@@ -24,6 +27,7 @@ pub fn key_path(key: &Option<PathBuf>) -> Result<PathBuf, DrawerError> {
|
|||||||
Ok(PathBuf::from(val))
|
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> {
|
pub fn identity(key: &Option<PathBuf>, drawer_file: &Path) -> Result<(PathBuf, Identity), DrawerError> {
|
||||||
let kp = key_path(key)?;
|
let kp = key_path(key)?;
|
||||||
let file = std::fs::File::open(&kp)
|
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))
|
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> {
|
pub fn decrypt(encrypted: Vec<u8>, key: &Option<PathBuf>, drawer_file: &Path) -> Result<Vec<u8>, DrawerError> {
|
||||||
let (kp, id) = identity(key, drawer_file)?;
|
let (kp, id) = identity(key, drawer_file)?;
|
||||||
let decryptor = age::Decryptor::new(encrypted.as_slice())
|
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)
|
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> {
|
pub fn encrypt(buf: &[u8], key: &Option<PathBuf>, drawer_file: &Path) -> Result<Vec<u8>, DrawerError> {
|
||||||
let (_, id) = identity(key, drawer_file)?;
|
let (_, id) = identity(key, drawer_file)?;
|
||||||
let recipient = age::ssh::Recipient::try_from(id)
|
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)
|
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 {
|
pub fn default_target(drawer_file: &Path, single_file: Option<&Path>) -> PathBuf {
|
||||||
match single_file {
|
match single_file {
|
||||||
Some(p) => PathBuf::from(p.file_name().unwrap_or_default()),
|
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> {
|
pub fn validate_drawer_extension(drawer_file: &Path) -> Result<(), DrawerError> {
|
||||||
if drawer_file.extension().and_then(|e| e.to_str()) != Some("drawer") {
|
if drawer_file.extension().and_then(|e| e.to_str()) != Some("drawer") {
|
||||||
return Err(DrawerError::DrawerFileInvalidExtension(drawer_file.to_path_buf()));
|
return Err(DrawerError::DrawerFileInvalidExtension(drawer_file.to_path_buf()));
|
||||||
@@ -75,6 +84,7 @@ pub fn validate_drawer_extension(drawer_file: &Path) -> Result<(), DrawerError>
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors if `drawer_file` does not exist on disk.
|
||||||
pub fn validate_drawer_file_exists(drawer_file: &Path) -> Result<(), DrawerError> {
|
pub fn validate_drawer_file_exists(drawer_file: &Path) -> Result<(), DrawerError> {
|
||||||
if !drawer_file.exists() {
|
if !drawer_file.exists() {
|
||||||
return Err(DrawerError::DrawerFileNotFound(drawer_file.to_path_buf()));
|
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(())
|
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> {
|
pub fn validate_ssh_key(key: &Option<PathBuf>) -> Result<(), DrawerError> {
|
||||||
let kp = key_path(key)?;
|
let kp = key_path(key)?;
|
||||||
let file = std::fs::File::open(&kp)
|
let file = std::fs::File::open(&kp)
|
||||||
|
|||||||
Reference in New Issue
Block a user