diff --git a/.gitignore b/.gitignore index 6b96577d..42aae610 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ perf.data perf.data.old workspace.code-workspace .cargo/config.toml +**.vach diff --git a/Cargo.lock b/Cargo.lock index 32e0bbc1..2efd7534 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,9 +75,9 @@ checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] name = "atty" @@ -453,19 +453,6 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" -[[package]] -name = "env_logger" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" -dependencies = [ - "humantime", - "is-terminal", - "log", - "regex", - "termcolor", -] - [[package]] name = "errno" version = "0.3.8" @@ -552,12 +539,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "indexmap" version = "1.9.3" @@ -570,9 +551,9 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" dependencies = [ "console", "instant", @@ -824,16 +805,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" -[[package]] -name = "pretty_env_logger" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" -dependencies = [ - "env_logger", - "log", -] - [[package]] name = "proc-macro-error" version = "1.0.4" @@ -1285,13 +1256,11 @@ dependencies = [ [[package]] name = "vach-cli" -version = "0.5.5" +version = "0.5.6" dependencies = [ "anyhow", "clap 3.2.25", "indicatif", - "log", - "pretty_env_logger", "tabled", "term_size", "vach 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1306,9 +1275,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", diff --git a/vach-cli/Cargo.toml b/vach-cli/Cargo.toml index 4a031738..fa2449c3 100644 --- a/vach-cli/Cargo.toml +++ b/vach-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vach-cli" -version = "0.5.5" +version = "0.5.6" edition = "2021" authors = [ "Jasper Fortuin ", @@ -21,10 +21,8 @@ path = "src/main.rs" [dependencies] vach = { version = "0.5.5", features = ["all"] } clap = "3.1.15" -indicatif = "0.17.6" -anyhow = "1.0.57" +indicatif = "0.17.8" +anyhow = "1.0.81" tabled = "0.15.0" -log = "0.4.17" -walkdir = "2.3.2" -pretty_env_logger = "0.5.0" +walkdir = "2.5.0" term_size = "0.3.2" diff --git a/vach-cli/src/app/mod.rs b/vach-cli/src/app/mod.rs index 16caa965..3e85d57b 100644 --- a/vach-cli/src/app/mod.rs +++ b/vach-cli/src/app/mod.rs @@ -56,6 +56,17 @@ pub fn build_app<'a>(key_map: HashMap<&'static str, Arg<'a>>) -> Command<'a> { .arg(key_map.get(key_names::PUBLIC_KEY).unwrap()) .arg(key_map.get(key_names::TRUNCATE).unwrap()), ) + .subcommand( + Command::new("pipe") + .author(AUTHORS) + .version(commands::pipe::VERSION) + .about("Pipes the contents of a .vach archive to stdout") + .arg(key_map.get(key_names::INPUT).unwrap()) + .arg(key_map.get(key_names::MAGIC).unwrap()) + .arg(key_map.get(key_names::PUBLIC_KEY).unwrap()) + .arg(key_map.get(key_names::RESOURCE).unwrap()) + .arg(key_map.get(key_names::KEYPAIR).unwrap()), + ) .subcommand( Command::new("pack") .author(AUTHORS) diff --git a/vach-cli/src/commands/keypair.rs b/vach-cli/src/commands/keypair.rs index 62de29b4..4c38ab42 100644 --- a/vach-cli/src/commands/keypair.rs +++ b/vach-cli/src/commands/keypair.rs @@ -30,13 +30,13 @@ impl CommandTrait for Evaluator { pk_path.push_str(".pk"); utils::create_and_write_to_file(&sk_path, &kp.to_bytes())?; - log::info!("Secret Key successfully generated and saved in: {}", sk_path); + println!("Secret Key successfully generated and saved in: {}", sk_path); utils::create_and_write_to_file(&pk_path, &kp.verifying_key().to_bytes())?; - log::info!("Public Key successfully generated and saved in: {}", pk_path); + println!("Public Key successfully generated and saved in: {}", pk_path); } else { utils::create_and_write_to_file(&output_path, &kp.to_keypair_bytes())?; - log::info!("KeyPair successfully generated and saved in: {}", output_path); + println!("KeyPair successfully generated and saved in: {}", output_path); } Ok(()) diff --git a/vach-cli/src/commands/mod.rs b/vach-cli/src/commands/mod.rs index 6ef408af..f7e7b4e0 100644 --- a/vach-cli/src/commands/mod.rs +++ b/vach-cli/src/commands/mod.rs @@ -15,6 +15,7 @@ pub trait CommandTrait: Sync { pub mod keypair; pub mod list; pub mod pack; +pub mod pipe; pub mod split; pub mod unpack; pub mod verify; @@ -28,6 +29,7 @@ pub fn build_commands() -> HashMap<&'static str, Box> { map.insert("list", Box::new(list::Evaluator)); map.insert("unpack", Box::new(unpack::Evaluator)); map.insert("pack", Box::new(pack::Evaluator)); + map.insert("pipe", Box::new(pipe::Evaluator)); map } diff --git a/vach-cli/src/commands/pack.rs b/vach-cli/src/commands/pack.rs index 76bb0a2b..e0a5c3d3 100644 --- a/vach-cli/src/commands/pack.rs +++ b/vach-cli/src/commands/pack.rs @@ -92,7 +92,7 @@ impl CommandTrait for Evaluator { match path.canonicalize() { Ok(path) => Some(path), Err(err) => { - log::warn!( + eprintln!( "Failed to evaluate: {}. Skipping due to error: {}", path.to_string_lossy(), err @@ -113,7 +113,7 @@ impl CommandTrait for Evaluator { let path_filter = |path: &PathBuf| match path.canonicalize() { Ok(canonical) => !excludes.contains(&canonical) && canonical.is_file(), Err(err) => { - log::warn!( + eprintln!( "Failed to evaluate: {}. Skipping due to error: {}", path.to_string_lossy(), err @@ -183,7 +183,7 @@ impl CommandTrait for Evaluator { let mut file = File::create("keypair.kp")?; file.write_all(&generated.to_keypair_bytes())?; - log::info!("Generated a new keypair @ keypair.kp"); + println!("Generated a new keypair @ keypair.kp"); kp = Some(generated); } @@ -247,7 +247,7 @@ impl CommandTrait for Evaluator { .trim_start_matches("./") .trim_start_matches(".\\") .to_string(); - log::info!("Preparing {} for packaging", id); + println!("Preparing {} for packaging", id); builder.add(wrapper, &id)?; } diff --git a/vach-cli/src/commands/pipe.rs b/vach-cli/src/commands/pipe.rs new file mode 100644 index 00000000..df816df6 --- /dev/null +++ b/vach-cli/src/commands/pipe.rs @@ -0,0 +1,79 @@ +use std::{ + fs::File, + io::{self, BufReader, Write}, +}; +use vach::{crypto_utils, prelude::*}; + +use super::CommandTrait; +use crate::keys::key_names; + +pub const VERSION: &str = "0.1.0"; + +pub struct Evaluator; + +impl CommandTrait for Evaluator { + fn evaluate(&self, args: &clap::ArgMatches) -> anyhow::Result<()> { + let input_path = match args.value_of(key_names::INPUT) { + Some(path) => path, + None => anyhow::bail!("Please provide an input path using the -i or --input key"), + }; + + let resource = match args.value_of(key_names::RESOURCE) { + Some(resource) => resource, + None => anyhow::bail!("Please provide a resource to extract using the -r or --resource key"), + }; + + let magic: [u8; vach::MAGIC_LENGTH] = match args.value_of(key_names::MAGIC) { + Some(magic) => magic.as_bytes().try_into()?, + None => *vach::DEFAULT_MAGIC, + }; + + // Attempting to extract a public key from a -p or -k input + let public_key = match args.value_of(key_names::KEYPAIR) { + Some(path) => { + let file = match File::open(path) { + Ok(it) => it, + Err(err) => anyhow::bail!("IOError: {} @ {}", err, path), + }; + + Some(crypto_utils::read_keypair(file)?.verifying_key()) + }, + None => match args.value_of(key_names::PUBLIC_KEY) { + Some(path) => { + let file = File::open(path)?; + Some(crypto_utils::read_public_key(file)?) + }, + None => None, + }, + }; + + let input_file = match File::open(input_path) { + Ok(it) => BufReader::new(it), + Err(err) => anyhow::bail!("IOError: {} @ {}", err, input_path), + }; + + // Generate ArchiveConfig using given magic and public key + let header_config = ArchiveConfig::new(magic, public_key); + + // Parse then extract archive + let mut archive = match Archive::with_config(input_file, &header_config) { + Ok(archive) => archive, + Err(err) => match err { + InternalError::NoKeypairError => anyhow::bail!( + "Please provide a public key or a keypair for use in decryption or signature verification" + ), + InternalError::MalformedArchiveSource(_) => anyhow::bail!("Unable to validate the archive: {}", err), + err => anyhow::bail!("Encountered an error: {}", err.to_string()), + }, + }; + + let stdout = io::stdout(); + { + let mut handle = stdout.lock(); + let resource = archive.fetch_mut(resource)?; + handle.write_all(&resource.data)?; + } + + Ok(()) + } +} diff --git a/vach-cli/src/commands/split.rs b/vach-cli/src/commands/split.rs index 44f9cf5a..6efac485 100644 --- a/vach-cli/src/commands/split.rs +++ b/vach-cli/src/commands/split.rs @@ -35,11 +35,9 @@ impl CommandTrait for Evaluator { utils::create_and_write_to_file(&pk_path, &kp.verifying_key().to_bytes())?; utils::create_and_write_to_file(&sk_path, &kp.to_bytes())?; - log::info!( + println!( "Successfully split keypair: {} -> into {} and {}", - input_path, - pk_path, - sk_path + input_path, pk_path, sk_path ); Ok(()) diff --git a/vach-cli/src/commands/unpack.rs b/vach-cli/src/commands/unpack.rs index e4953840..d9cfdb7c 100644 --- a/vach-cli/src/commands/unpack.rs +++ b/vach-cli/src/commands/unpack.rs @@ -1,6 +1,6 @@ use std::fs::{self, File}; use std::str::FromStr; -use std::io::{Read, Seek, Write}; +use std::io::{BufReader, Read, Seek, Write}; use std::path::PathBuf; use std::time::Instant; @@ -12,7 +12,7 @@ use indicatif::{ProgressBar, ProgressStyle}; use super::CommandTrait; use crate::keys::key_names; -pub const VERSION: &str = "0.1.0"; +pub const VERSION: &str = "0.1.1"; /// This command extracts an archive into the specified output folder pub struct Evaluator; @@ -61,7 +61,7 @@ impl CommandTrait for Evaluator { let truncate = args.is_present(key_names::TRUNCATE); let input_file = match File::open(input_path) { - Ok(it) => it, + Ok(it) => BufReader::new(it), Err(err) => anyhow::bail!("IOError: {} @ {}", err, input_path), }; @@ -84,7 +84,7 @@ impl CommandTrait for Evaluator { // Delete original archive if truncate { - log::info!("Truncating original archive @ {}", &input_path); + println!("Truncating original archive @ {}", &input_path); std::fs::remove_file(input_path)?; }; @@ -141,7 +141,7 @@ fn extract_archive(archive: &Archive, target_fo // Finished extracting pbar.finish(); - log::info!( + println!( "Extracted {} files in {}s", archive.entries().len(), time.elapsed().as_secs_f64() diff --git a/vach-cli/src/keys/mod.rs b/vach-cli/src/keys/mod.rs index 87a7161d..3363aa6f 100644 --- a/vach-cli/src/keys/mod.rs +++ b/vach-cli/src/keys/mod.rs @@ -4,6 +4,7 @@ use std::collections::HashMap; pub mod key_names { pub(crate) const OUTPUT: &str = "OUTPUT"; pub(crate) const INPUT: &str = "INPUT"; + pub(crate) const RESOURCE: &str = "RESOURCE"; pub(crate) const DIR_INPUT: &str = "DIR_INPUT"; pub(crate) const DIR_INPUT_REC: &str = "DIR_INPUT_REC"; @@ -45,6 +46,19 @@ pub fn build_keys<'a>() -> HashMap<&'static str, Arg<'a>> { .number_of_values(1), ); + // A resource to focus on and extract + map.insert( + key_names::RESOURCE, + Arg::new(key_names::RESOURCE) + .short('r') + .long("resource") + .value_name(key_names::RESOURCE) + .help("An exact resource to extract from the archive") + .required(false) + .takes_value(true) + .number_of_values(1), + ); + // A general input source map.insert( key_names::INPUT, diff --git a/vach-cli/src/keys/utils/mod.rs b/vach-cli/src/keys/utils/mod.rs deleted file mode 100644 index e2079205..00000000 --- a/vach-cli/src/keys/utils/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -use std::path::PathBuf; -use std::fs::File; -use std::io::Write; -use std::str::FromStr; -use anyhow::{Result, bail}; - -pub fn create_and_write_to_file(path: &str, data: &[u8]) -> Result<()> { - let path = PathBuf::from_str(path)?; - - // Check if the file exists - if path.exists() { - bail!("The file {} already exists!", path.to_string_lossy()); - } - - let mut file = File::create(path)?; - file.write_all(data)?; - - Ok(()) -} diff --git a/vach-cli/src/main.rs b/vach-cli/src/main.rs index 633faaff..86be4a4a 100644 --- a/vach-cli/src/main.rs +++ b/vach-cli/src/main.rs @@ -6,8 +6,6 @@ mod utils; // NOTE: Unwrapping in a CLI is a no-no. Since throwing Rust developer errors at average users is mental overload fn main() { - pretty_env_logger::init(); - // Build CLI let keys = keys::build_keys(); let app = app::build_app(keys); @@ -16,15 +14,12 @@ fn main() { // Start CLI let matches = app.get_matches(); - let res = match matches.subcommand() { + match matches.subcommand() { Some((key, mtx)) => commands.get(key).unwrap().evaluate(mtx), None => { println!("vach-cli: Run `vach --help` and refer to crates.io/vach-cli for the manual"); Ok(()) }, - }; - - if let Err(err) = res { - log::error!("{}", err) - }; + } + .unwrap(); }