use std::{collections::BTreeMap, path::PathBuf};
use chrono::Utc;
use sett::{
decrypt::{decrypt, DecryptOpts},
encrypt::{encrypt, EncryptOpts},
openpgp::{certstore::CertStore, keystore::KeyStore},
package::{Package, CHECKSUM_FILE, CONTENT_FOLDER},
task::Mode,
utils::Progress,
};
const PASSWORD: &[u8] = b"secret";
struct ProgressNoop;
impl Progress for ProgressNoop {
fn set_length(&mut self, _len: u64) {}
fn inc(&mut self, _delta: u64) {}
fn finish(&mut self) {}
}
async fn encrypt_password_prompt(
_hint: sett::openpgp::types::PasswordHint,
) -> sett::openpgp::types::Password {
PASSWORD.into()
}
fn decrypt_password_prompt(
_hint: sett::openpgp::types::PasswordHint,
) -> sett::openpgp::types::Password {
PASSWORD.into()
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn roundtrip() {
encrypt_and_decrypt(BTreeMap::from([
("foo".into(), "bar".into()),
("baz".into(), "qux".into()),
]))
.await;
encrypt_and_decrypt(Default::default()).await;
}
async fn encrypt_and_decrypt(extra_metadata: BTreeMap<String, String>) {
const PASSWORD: &[u8] = b"secret";
const MESSAGE: &[u8] = b"A very secret message!";
let mut cert_store = CertStore::open_ephemeral();
let mut key_store = KeyStore::open_ephemeral().await.unwrap();
let (cert, _rev) = sett::openpgp::cert::CertBuilder::new()
.add_userid("Chuck <chuck@example.org>")
.set_password(Some(PASSWORD.into()))
.generate()
.unwrap();
cert_store.import(&cert).unwrap();
key_store.import(cert.clone()).await.unwrap();
let tmp_dir = tempfile::tempdir().unwrap();
let test_file = tmp_dir.path().join("test.txt");
std::fs::write(&test_file, MESSAGE).unwrap();
let status = encrypt(
EncryptOpts {
files: vec![test_file.to_path_buf()],
recipients: vec![cert.fingerprint()],
signer: cert.fingerprint(),
cert_store,
key_store,
password: encrypt_password_prompt,
compression_algorithm: Default::default(),
mode: Mode::Run,
progress: None::<ProgressNoop>,
purpose: None,
transfer_id: None,
timestamp: Utc::now(),
prefix: None,
extra_metadata: extra_metadata.clone(),
},
sett::destination::Local::new(tmp_dir.path(), None::<String>)
.unwrap()
.into(),
)
.await
.unwrap();
let package_path = match status {
sett::task::Status::Completed { destination, .. } => destination,
_ => panic!("Expected completed status"),
};
let mut cert_store = CertStore::open_ephemeral();
cert_store.import(&cert).unwrap();
let mut key_store = KeyStore::open_ephemeral().await.unwrap();
key_store.import(cert.clone()).await.unwrap();
let decrypt_opts = DecryptOpts {
package: Package::open(package_path).await.unwrap(),
key_store,
cert_store,
password: decrypt_password_prompt,
output: Some(tmp_dir.path().to_path_buf()),
mode: Mode::Run,
decrypt_only: false,
progress: None::<ProgressNoop>,
};
let package = decrypt_opts
.package
.clone()
.verify(&decrypt_opts.cert_store)
.await
.unwrap();
let pkg_metadata = package.metadata().await.unwrap();
let status = decrypt(decrypt_opts).await.unwrap();
let unpacked_package = match status {
sett::task::Status::Completed { destination, .. } => PathBuf::from(destination),
_ => panic!("Expected completed status"),
};
assert!(unpacked_package.join(CHECKSUM_FILE).exists());
let decrypted_file_path = unpacked_package.join(CONTENT_FOLDER).join("test.txt");
assert_eq!(std::fs::read(decrypted_file_path).unwrap(), MESSAGE);
assert_eq!(pkg_metadata.extra, extra_metadata);
}
}