This commit is contained in:
2026-05-10 18:27:55 -05:00
parent 619ac5f9d1
commit 33f567d2bc
3 changed files with 48 additions and 9 deletions
+7
View File
@@ -106,6 +106,13 @@ I'm going to add some test data to the project under `tests/` but it's just rand
As a minor improvement, make the `perform_close` method also gzip the contents of the tarball.
### Phase 4
For phase 4, add encryption. We'll have to add a new error type for the given key not being a valid key for `age`.
Now, after we create the tar but before we write it to disk, we need to encrypt the array, so that plaintext is never
written to disk.
## Commands
```bash
+4
View File
@@ -13,6 +13,8 @@ pub enum DrawerError {
DrawerInsideTarget,
TarFailed,
WriteFailed(PathBuf),
KeyNotValidSsh,
EncryptFailed,
}
impl fmt::Display for DrawerError {
@@ -28,6 +30,8 @@ impl fmt::Display for DrawerError {
DrawerError::DrawerInsideTarget => write!(f, "drawer file is inside the target directory"),
DrawerError::TarFailed => write!(f, "failed to create tarball"),
DrawerError::WriteFailed(p) => write!(f, "failed to write drawer file: {}", p.display()),
DrawerError::KeyNotValidSsh => write!(f, "key is not a valid SSH key"),
DrawerError::EncryptFailed => write!(f, "encryption failed"),
}
}
}
+37 -9
View File
@@ -1,4 +1,5 @@
use std::ffi::OsString;
use std::io::Write;
use std::path::{Path, PathBuf};
use flate2::Compression;
use flate2::write::GzEncoder;
@@ -119,7 +120,26 @@ impl DrawerOperation {
gz.finish()
.map_err(|_| DrawerError::TarFailed)?;
}
std::fs::write(&self.drawer_file, &buf)
let key_path = self.key_path()?;
let file = std::fs::File::open(&key_path)
.map_err(|_| DrawerError::KeyInvalid(key_path.clone()))?;
let reader = std::io::BufReader::new(file);
let identity = age::ssh::Identity::from_buffer(reader, None)
.map_err(|_| DrawerError::EncryptFailed)?;
let recipient = age::ssh::Recipient::try_from(identity)
.map_err(|_| DrawerError::EncryptFailed)?;
let mut encrypted: Vec<u8> = Vec::new();
let encryptor = age::Encryptor::with_recipients(
std::iter::once(&recipient as &dyn age::Recipient)
).map_err(|_| DrawerError::EncryptFailed)?;
let mut writer = encryptor.wrap_output(&mut encrypted)
.map_err(|_| DrawerError::EncryptFailed)?;
writer.write_all(&buf).map_err(|_| DrawerError::EncryptFailed)?;
writer.finish().map_err(|_| DrawerError::EncryptFailed)?;
std::fs::write(&self.drawer_file, &encrypted)
.map_err(|_| DrawerError::WriteFailed(self.drawer_file.clone()))
}
@@ -134,20 +154,28 @@ impl DrawerOperation {
}
}
fn validate_key(&self) -> Result<(), DrawerError> {
let key_path = match &self.key {
fn key_path(&self) -> Result<PathBuf, DrawerError> {
match &self.key {
EnvVar => {
let val = std::env::var("DRAWER_KEY").map_err(|_| DrawerError::NoKeyPath)?;
PathBuf::from(val)
Ok(PathBuf::from(val))
}
Path(p) => p.clone(),
};
match std::fs::File::open(&key_path) {
Ok(_) => Ok(()),
Err(_) => Err(DrawerError::KeyInvalid(key_path)),
Path(p) => Ok(p.clone()),
}
}
fn validate_key(&self) -> Result<(), DrawerError> {
let key_path = self.key_path()?;
let file = std::fs::File::open(&key_path)
.map_err(|_| DrawerError::KeyInvalid(key_path.clone()))?;
let reader = std::io::BufReader::new(file);
let identity = age::ssh::Identity::from_buffer(reader, None)
.map_err(|_| DrawerError::KeyNotValidSsh)?;
age::ssh::Recipient::try_from(identity)
.map_err(|_| DrawerError::KeyNotValidSsh)?;
Ok(())
}
fn validate_open(&self) -> Result<(), DrawerError> {
if !self.drawer_file.exists() {
return Err(DrawerError::DrawerFileNotFound(self.drawer_file.clone()));