From 60b2c6805796b7c88028ebe1584efa97ce1ab66c Mon Sep 17 00:00:00 2001 From: Robert Li Date: Wed, 27 Mar 2024 16:30:08 +1100 Subject: [PATCH 01/13] fix: benchmark unzip from uri command --- trial-uri.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trial-uri.sh b/trial-uri.sh index 3b03432..d3b7c35 100755 --- a/trial-uri.sh +++ b/trial-uri.sh @@ -20,7 +20,7 @@ rm -Rf /tmp/testb mkdir /tmp/testb pushd /tmp/testb echo ripunzip: -time sh -c "$MYDIR/target/release/ripunzip uri \"$URI\" " +time sh -c "$MYDIR/target/release/ripunzip unzip-uri \"$URI\" " popd rm -Rf /tmp/testb From ad38796cc87514ca5999a1a0e21c305aa9455d08 Mon Sep 17 00:00:00 2001 From: Robert Li Date: Wed, 27 Mar 2024 18:24:04 +1100 Subject: [PATCH 02/13] chore: add password option --- src/main.rs | 5 +++++ src/unzip/mod.rs | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/src/main.rs b/src/main.rs index 9f4a2a8..45b57d7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -73,6 +73,10 @@ struct UnzipArgs { #[arg(short = 'd', long, value_name = "DIRECTORY")] output_directory: Option, + /// Password to decrypt encrypted zipfile entries (if any). THIS IS INSECURE! + #[arg(short = 'P', long, value_name = "PASSWORD")] + password: Option, + /// Whether to decompress on a single thread. By default, /// multiple threads are used, but this can lead to more network traffic. #[arg(long)] @@ -152,6 +156,7 @@ fn unzip(engine: UnzipEngine, unzip_args: UnzipArgs, is_silent: bool) -> Result< }; let options = UnzipOptions { output_directory: unzip_args.output_directory, + password: unzip_args.password, single_threaded: unzip_args.single_threaded, filename_filter, progress_reporter, diff --git a/src/unzip/mod.rs b/src/unzip/mod.rs index ebfd9fc..b910507 100644 --- a/src/unzip/mod.rs +++ b/src/unzip/mod.rs @@ -36,6 +36,8 @@ use self::{ pub struct UnzipOptions { /// The destination directory. pub output_directory: Option, + /// Password if encrypted. + pub password: Option, /// Whether to run in single-threaded mode. pub single_threaded: bool, /// A filename filter, optionally @@ -552,6 +554,7 @@ mod tests { set_current_dir(td.path()).unwrap(); let options = UnzipOptions { output_directory: None, + password: None, single_threaded: false, filename_filter, progress_reporter: Box::new(NullProgressReporter), @@ -572,6 +575,7 @@ mod tests { let outdir = td.path().join("outdir"); let options = UnzipOptions { output_directory: Some(outdir.clone()), + password: None, single_threaded: false, filename_filter, progress_reporter: Box::new(NullProgressReporter), @@ -617,6 +621,7 @@ mod tests { let outdir = td.path().join("outdir"); let options = UnzipOptions { output_directory: Some(outdir.clone()), + password: None, single_threaded: false, filename_filter, progress_reporter: Box::new(NullProgressReporter), @@ -639,6 +644,7 @@ mod tests { let outdir = td.path().join("outdir"); let options = UnzipOptions { output_directory: Some(outdir), + password: None, single_threaded: false, filename_filter: None, progress_reporter: Box::new(NullProgressReporter), From 2ee68192f480bd08f9ddd109aab2bf0068897c31 Mon Sep 17 00:00:00 2001 From: Robert Li Date: Wed, 27 Mar 2024 18:56:18 +1100 Subject: [PATCH 03/13] chore: implement decrypt for file index --- src/unzip/mod.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/unzip/mod.rs b/src/unzip/mod.rs index b910507..bdfd1a7 100644 --- a/src/unzip/mod.rs +++ b/src/unzip/mod.rs @@ -278,6 +278,7 @@ fn unzip_serial_or_parallel<'a, T: Read + Seek + 'a>( &get_ziparchive_clone, i, &options.output_directory, + &options.password, progress_reporter, directory_creator, ) @@ -299,6 +300,7 @@ fn unzip_serial_or_parallel<'a, T: Read + Seek + 'a>( &get_ziparchive_clone, i, &options.output_directory, + &options.password, progress_reporter, directory_creator, ) @@ -361,12 +363,22 @@ fn extract_file_by_index<'a, T: Read + Seek + 'a>( get_ziparchive_clone: impl Fn() -> ZipArchive + Sync, i: usize, output_directory: &Option, + password: &Option, progress_reporter: &dyn UnzipProgressReporter, directory_creator: &DirectoryCreator, ) -> Result<(), anyhow::Error> { let myzip: &mut zip::ZipArchive = &mut get_ziparchive_clone(); - let file = myzip.by_index(i)?; - extract_file(file, output_directory, progress_reporter, directory_creator) + match password { + None => { + let file = myzip.by_index(i)?; + extract_file(file, output_directory, progress_reporter, directory_creator) + + } + Some(string) => { + let file = myzip.by_index_decrypt(i, string.as_bytes())??; + extract_file(file, output_directory, progress_reporter, directory_creator) + } + } } fn extract_file( From b5a72d4e7e58d0f5ff43f506d838953c3a20e1a7 Mon Sep 17 00:00:00 2001 From: Robert Li Date: Wed, 27 Mar 2024 19:02:33 +1100 Subject: [PATCH 04/13] chore: implement decrypt for file name --- src/unzip/mod.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/unzip/mod.rs b/src/unzip/mod.rs index bdfd1a7..8485e82 100644 --- a/src/unzip/mod.rs +++ b/src/unzip/mod.rs @@ -343,7 +343,15 @@ fn unzip_serial_or_parallel<'a, T: Read + Seek + 'a>( .into_iter() .map(|name| { let myzip: &mut zip::ZipArchive = &mut get_ziparchive_clone(); - let file = myzip.by_name(&name)?; + let file: ZipFile; + match &options.password { + None => { + file = myzip.by_name(&name)?; + } + Some(string) => { + file = myzip.by_name_decrypt(&name, string.as_bytes())??; + } + } let r = extract_file( file, &options.output_directory, @@ -368,14 +376,15 @@ fn extract_file_by_index<'a, T: Read + Seek + 'a>( directory_creator: &DirectoryCreator, ) -> Result<(), anyhow::Error> { let myzip: &mut zip::ZipArchive = &mut get_ziparchive_clone(); + let file: ZipFile; match password { None => { - let file = myzip.by_index(i)?; + file = myzip.by_index(i)?; extract_file(file, output_directory, progress_reporter, directory_creator) } Some(string) => { - let file = myzip.by_index_decrypt(i, string.as_bytes())??; + file = myzip.by_index_decrypt(i, string.as_bytes())??; extract_file(file, output_directory, progress_reporter, directory_creator) } } From b9a52337b9b55e4c6a04fdc1a6b40e7e843a4427 Mon Sep 17 00:00:00 2001 From: Robert Li Date: Wed, 27 Mar 2024 19:41:31 +1100 Subject: [PATCH 05/13] chore: add passworded zip resource to test --- src/unzip/mod.rs | 21 +++++++++++++++++++++ test_resources/z_with_password.zip | Bin 0 -> 582 bytes 2 files changed, 21 insertions(+) create mode 100644 test_resources/z_with_password.zip diff --git a/src/unzip/mod.rs b/src/unzip/mod.rs index 8485e82..4e12442 100644 --- a/src/unzip/mod.rs +++ b/src/unzip/mod.rs @@ -504,6 +504,7 @@ mod tests { io::{Cursor, Seek, Write}, path::Path, }; + use std::path::PathBuf; use tempfile::tempdir; use test_log::test; use zip::{write::FileOptions, ZipWriter}; @@ -606,6 +607,26 @@ mod tests { }); } + #[test] + fn test_extract_with_path_with_password() { + run_with_and_without_a_filename_filter(|create_a, filename_filter| { + let td = tempdir().unwrap(); + let mut zf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + zf.push("test_resources/z_with_password.zip"); + let zf = File::open(zf).unwrap(); + let outdir = td.path().join("outdir"); + let options = UnzipOptions { + output_directory: Some(outdir.clone()), + password: Some("1Password".to_string()), + single_threaded: false, + filename_filter, + progress_reporter: Box::new(NullProgressReporter), + }; + UnzipEngine::for_file(zf).unwrap().unzip(options).unwrap(); + check_files_exist(&outdir, create_a); + }); + } + #[test] fn test_list() { let td = tempdir().unwrap(); diff --git a/test_resources/z_with_password.zip b/test_resources/z_with_password.zip new file mode 100644 index 0000000000000000000000000000000000000000..1101ca2ebc005fcc7d64b7be0760fc0ee631de26 GIT binary patch literal 582 zcmWIWW@h1H;ACK62%B9UVQhMnMGDB~17cPN8HOail8Tbh5KabW=NrsvE z=))}H0$Nm(T3n)^2)E4xXp<+VZMXT>h6W~|=4=z*ttUHg`Gu2x?2~Uuo0n&u0ojIZ zCc?I8plwAghh#BqONQI#3$zJ@(fp>{e`N0hj-0&A7>T&rSzHdreDD9u%QxPCJ`H3W zvY7$ij7)OOxPnmv7)}ffzz}0t(g Date: Sat, 28 Sep 2024 15:16:18 +1000 Subject: [PATCH 06/13] chore: add test to create encrypted zip --- src/unzip/mod.rs | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/unzip/mod.rs b/src/unzip/mod.rs index 393d894..3bebf41 100644 --- a/src/unzip/mod.rs +++ b/src/unzip/mod.rs @@ -533,6 +533,11 @@ mod tests { create_zip(file, include_a_txt) } + fn create_encryped_zip_file(path: &Path, include_a_txt: bool) { + let file = File::create(path).unwrap(); + create_encrypted_zip(file, include_a_txt) + } + fn create_zip(w: impl Write + Seek, include_a_txt: bool) { let mut zip = ZipWriter::new(w); @@ -551,6 +556,25 @@ mod tests { zip.finish().unwrap(); } + fn create_encrypted_zip(w: impl Write + Seek, include_a_txt: bool,) { + let mut zip = ZipWriter::new(w); + + zip.add_directory("test/", Default::default()).unwrap(); + let options = FileOptions::default() + .compression_method(zip::CompressionMethod::Stored) + .unix_permissions(0o755) + .with_deprecated_encryption("1Password".as_ref()); + if include_a_txt { + zip.start_file("test/a.txt", options).unwrap(); + zip.write_all(b"Contents of A\n").unwrap(); + } + zip.start_file("b.txt", options).unwrap(); + zip.write_all(b"Contents of B\n").unwrap(); + zip.start_file("test/c.txt", options).unwrap(); + zip.write_all(b"Contents of C\n").unwrap(); + zip.finish().unwrap(); + } + fn check_files_exist(path: &Path, include_a_txt: bool) { let a = path.join("test/a.txt"); let b = path.join("b.txt"); @@ -607,6 +631,26 @@ mod tests { }); } + #[test] + fn test_extract_encrypted_with_path() { + run_with_and_without_a_filename_filter(|create_a, filename_filter| { + let td = tempdir().unwrap(); + let zf = td.path().join("z.zip"); + create_encryped_zip_file(&zf, create_a); + let zf = File::open(zf).unwrap(); + let outdir = td.path().join("outdir"); + let options = UnzipOptions { + output_directory: Some(outdir.clone()), + password: Some("1Password".to_string()), + single_threaded: false, + filename_filter, + progress_reporter: Box::new(NullProgressReporter), + }; + UnzipEngine::for_file(zf).unwrap().unzip(options).unwrap(); + check_files_exist(&outdir, create_a); + }); + } + #[test] fn test_extract_with_path_with_password() { run_with_and_without_a_filename_filter(|create_a, filename_filter| { @@ -644,7 +688,7 @@ mod tests { } use httptest::Server; - + use zip::unstable::write::FileOptionsExt; use super::FilenameFilter; #[test] From 62a215d6d5b2e4b4509bf01804c3feee84bf559c Mon Sep 17 00:00:00 2001 From: Robert Li Date: Sat, 28 Sep 2024 15:20:36 +1000 Subject: [PATCH 07/13] chore: remove the need for test resource --- src/unzip/mod.rs | 21 --------------------- test_resources/z_with_password.zip | Bin 582 -> 0 bytes 2 files changed, 21 deletions(-) delete mode 100644 test_resources/z_with_password.zip diff --git a/src/unzip/mod.rs b/src/unzip/mod.rs index 3bebf41..8086cbb 100644 --- a/src/unzip/mod.rs +++ b/src/unzip/mod.rs @@ -504,7 +504,6 @@ mod tests { io::{Cursor, Seek, Write}, path::Path, }; - use std::path::PathBuf; use tempfile::tempdir; use test_log::test; use zip::{write::FileOptions, ZipWriter}; @@ -651,26 +650,6 @@ mod tests { }); } - #[test] - fn test_extract_with_path_with_password() { - run_with_and_without_a_filename_filter(|create_a, filename_filter| { - let td = tempdir().unwrap(); - let mut zf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - zf.push("test_resources/z_with_password.zip"); - let zf = File::open(zf).unwrap(); - let outdir = td.path().join("outdir"); - let options = UnzipOptions { - output_directory: Some(outdir.clone()), - password: Some("1Password".to_string()), - single_threaded: false, - filename_filter, - progress_reporter: Box::new(NullProgressReporter), - }; - UnzipEngine::for_file(zf).unwrap().unzip(options).unwrap(); - check_files_exist(&outdir, create_a); - }); - } - #[test] fn test_list() { let td = tempdir().unwrap(); diff --git a/test_resources/z_with_password.zip b/test_resources/z_with_password.zip deleted file mode 100644 index 1101ca2ebc005fcc7d64b7be0760fc0ee631de26..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 582 zcmWIWW@h1H;ACK62%B9UVQhMnMGDB~17cPN8HOail8Tbh5KabW=NrsvE z=))}H0$Nm(T3n)^2)E4xXp<+VZMXT>h6W~|=4=z*ttUHg`Gu2x?2~Uuo0n&u0ojIZ zCc?I8plwAghh#BqONQI#3$zJ@(fp>{e`N0hj-0&A7>T&rSzHdreDD9u%QxPCJ`H3W zvY7$ij7)OOxPnmv7)}ffzz}0t(g Date: Sat, 28 Sep 2024 15:24:57 +1000 Subject: [PATCH 08/13] chore: fix doco --- src/main.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 3af054b..431669f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,7 +19,7 @@ use ripunzip::{ use wildmatch::WildMatch; const LONG_ABOUT: &str = - "ripunzip is a tool to unzip zip files in parallel, possibly from a remote server. + "ripunzip is a tool to unzip zip files in parallel, possibly from a remote server. It works best with HTTP(S) servers that support Range requests."; /// Unzip all files within a zip file as quickly as possible. @@ -73,7 +73,8 @@ struct UnzipArgs { #[arg(short = 'd', long, value_name = "DIRECTORY")] output_directory: Option, - /// Password to decrypt encrypted zipfile entries (if any). THIS IS INSECURE! + /// Password to decrypt encrypted zipfile entries (if any). + /// Encryption is assumed to be the ZipCrypto algorithm. #[arg(short = 'P', long, value_name = "PASSWORD")] password: Option, From 40c68a6811ad8b871fe59ebe7429a386c4cdb88d Mon Sep 17 00:00:00 2001 From: Robert Li Date: Sat, 28 Sep 2024 16:06:59 +1000 Subject: [PATCH 09/13] chore: fix clippy issue --- src/unzip/mod.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/unzip/mod.rs b/src/unzip/mod.rs index 8086cbb..c293d64 100644 --- a/src/unzip/mod.rs +++ b/src/unzip/mod.rs @@ -343,15 +343,14 @@ fn unzip_serial_or_parallel<'a, T: Read + Seek + 'a>( .into_iter() .map(|name| { let myzip: &mut zip::ZipArchive = &mut get_ziparchive_clone(); - let file: ZipFile; - match &options.password { + let file: ZipFile = match &options.password { None => { - file = myzip.by_name(&name)?; + myzip.by_name(&name)? } Some(string) => { - file = myzip.by_name_decrypt(&name, string.as_bytes())??; + myzip.by_name_decrypt(&name, string.as_bytes())?? } - } + }; let r = extract_file( file, &options.output_directory, From bdb2787051974a26ec74f40ea40d2b4680e4bb41 Mon Sep 17 00:00:00 2001 From: Robert Li Date: Sat, 28 Sep 2024 16:11:15 +1000 Subject: [PATCH 10/13] chore: fix formatting --- src/unzip/mod.rs | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/src/unzip/mod.rs b/src/unzip/mod.rs index c293d64..878a96c 100644 --- a/src/unzip/mod.rs +++ b/src/unzip/mod.rs @@ -344,12 +344,8 @@ fn unzip_serial_or_parallel<'a, T: Read + Seek + 'a>( .map(|name| { let myzip: &mut zip::ZipArchive = &mut get_ziparchive_clone(); let file: ZipFile = match &options.password { - None => { - myzip.by_name(&name)? - } - Some(string) => { - myzip.by_name_decrypt(&name, string.as_bytes())?? - } + None => myzip.by_name(&name)?, + Some(string) => myzip.by_name_decrypt(&name, string.as_bytes())??, }; let r = extract_file( file, @@ -380,7 +376,6 @@ fn extract_file_by_index<'a, T: Read + Seek + 'a>( None => { file = myzip.by_index(i)?; extract_file(file, output_directory, progress_reporter, directory_creator) - } Some(string) => { file = myzip.by_index_decrypt(i, string.as_bytes())??; @@ -496,6 +491,10 @@ impl DirectoryCreator { #[cfg(test)] mod tests { + use super::FilenameFilter; + use crate::{NullProgressReporter, UnzipEngine, UnzipOptions}; + use httptest::Server; + use ripunzip_test_utils::*; use std::{ collections::HashSet, env::{current_dir, set_current_dir}, @@ -505,11 +504,9 @@ mod tests { }; use tempfile::tempdir; use test_log::test; + use zip::unstable::write::FileOptionsExt; use zip::{write::FileOptions, ZipWriter}; - use crate::{NullProgressReporter, UnzipEngine, UnzipOptions}; - use ripunzip_test_utils::*; - struct UnzipSomeFilter; impl FilenameFilter for UnzipSomeFilter { fn should_unzip(&self, filename: &str) -> bool { @@ -554,7 +551,7 @@ mod tests { zip.finish().unwrap(); } - fn create_encrypted_zip(w: impl Write + Seek, include_a_txt: bool,) { + fn create_encrypted_zip(w: impl Write + Seek, include_a_txt: bool) { let mut zip = ZipWriter::new(w); zip.add_directory("test/", Default::default()).unwrap(); @@ -665,10 +662,6 @@ mod tests { ) } - use httptest::Server; - use zip::unstable::write::FileOptionsExt; - use super::FilenameFilter; - #[test] fn test_extract_from_server() { run_with_and_without_a_filename_filter(|create_a, filename_filter| { From 8569696f4360ad812ede21e848c2ef9c06a056a6 Mon Sep 17 00:00:00 2001 From: Robert Li Date: Sat, 28 Sep 2024 21:47:00 +1000 Subject: [PATCH 11/13] chore: re-factor dupe code --- src/unzip/mod.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/unzip/mod.rs b/src/unzip/mod.rs index 878a96c..15c23ce 100644 --- a/src/unzip/mod.rs +++ b/src/unzip/mod.rs @@ -371,17 +371,11 @@ fn extract_file_by_index<'a, T: Read + Seek + 'a>( directory_creator: &DirectoryCreator, ) -> Result<(), anyhow::Error> { let myzip: &mut zip::ZipArchive = &mut get_ziparchive_clone(); - let file: ZipFile; - match password { - None => { - file = myzip.by_index(i)?; - extract_file(file, output_directory, progress_reporter, directory_creator) - } - Some(string) => { - file = myzip.by_index_decrypt(i, string.as_bytes())??; - extract_file(file, output_directory, progress_reporter, directory_creator) - } - } + let file: ZipFile = match password { + None => myzip.by_index(i)?, + Some(string) => myzip.by_index_decrypt(i, string.as_bytes())??, + }; + extract_file(file, output_directory, progress_reporter, directory_creator) } fn extract_file( From eee49f6395c9872b08804b728988bf010ac43151 Mon Sep 17 00:00:00 2001 From: Robert Li Date: Sat, 28 Sep 2024 22:06:58 +1000 Subject: [PATCH 12/13] chore: re-factor remove dupes in zip contents code --- src/unzip/mod.rs | 40 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/src/unzip/mod.rs b/src/unzip/mod.rs index 15c23ce..5c6ea31 100644 --- a/src/unzip/mod.rs +++ b/src/unzip/mod.rs @@ -519,40 +519,28 @@ mod tests { fn create_zip_file(path: &Path, include_a_txt: bool) { let file = File::create(path).unwrap(); - create_zip(file, include_a_txt) + create_zip(file, include_a_txt, None) } - fn create_encryped_zip_file(path: &Path, include_a_txt: bool) { + fn create_encrypted_zip_file(path: &Path, include_a_txt: bool) { let file = File::create(path).unwrap(); - create_encrypted_zip(file, include_a_txt) - } - - fn create_zip(w: impl Write + Seek, include_a_txt: bool) { - let mut zip = ZipWriter::new(w); - - zip.add_directory("test/", Default::default()).unwrap(); let options = FileOptions::default() .compression_method(zip::CompressionMethod::Stored) - .unix_permissions(0o755); - if include_a_txt { - zip.start_file("test/a.txt", options).unwrap(); - zip.write_all(b"Contents of A\n").unwrap(); - } - zip.start_file("b.txt", options).unwrap(); - zip.write_all(b"Contents of B\n").unwrap(); - zip.start_file("test/c.txt", options).unwrap(); - zip.write_all(b"Contents of C\n").unwrap(); - zip.finish().unwrap(); + .unix_permissions(0o755) + .with_deprecated_encryption("1Password".as_ref()); + create_zip(file, include_a_txt, Some(options)) } - fn create_encrypted_zip(w: impl Write + Seek, include_a_txt: bool) { + fn create_zip(w: impl Write + Seek, include_a_txt: bool, custom_options: Option) { let mut zip = ZipWriter::new(w); + let options = custom_options.unwrap_or_else(|| { + FileOptions::default() + .compression_method(zip::CompressionMethod::Stored) + .unix_permissions(0o755) + }); zip.add_directory("test/", Default::default()).unwrap(); - let options = FileOptions::default() - .compression_method(zip::CompressionMethod::Stored) - .unix_permissions(0o755) - .with_deprecated_encryption("1Password".as_ref()); + if include_a_txt { zip.start_file("test/a.txt", options).unwrap(); zip.write_all(b"Contents of A\n").unwrap(); @@ -625,7 +613,7 @@ mod tests { run_with_and_without_a_filename_filter(|create_a, filename_filter| { let td = tempdir().unwrap(); let zf = td.path().join("z.zip"); - create_encryped_zip_file(&zf, create_a); + create_encrypted_zip_file(&zf, create_a); let zf = File::open(zf).unwrap(); let outdir = td.path().join("outdir"); let options = UnzipOptions { @@ -661,7 +649,7 @@ mod tests { run_with_and_without_a_filename_filter(|create_a, filename_filter| { let td = tempdir().unwrap(); let mut zip_data = Cursor::new(Vec::new()); - create_zip(&mut zip_data, create_a); + create_zip(&mut zip_data, create_a, None); let body = zip_data.into_inner(); println!("Whole zip:"); hexdump::hexdump(&body); From 84fbb0314e51f5f8909abe3b02994ee3097b6006 Mon Sep 17 00:00:00 2001 From: Robert Li Date: Sun, 29 Sep 2024 02:25:09 +1000 Subject: [PATCH 13/13] chore: clarify doco re decryption support --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 431669f..7aeea78 100644 --- a/src/main.rs +++ b/src/main.rs @@ -74,7 +74,7 @@ struct UnzipArgs { output_directory: Option, /// Password to decrypt encrypted zipfile entries (if any). - /// Encryption is assumed to be the ZipCrypto algorithm. + /// Both ZipCrypto and AES encrypted zipfiles are supported. #[arg(short = 'P', long, value_name = "PASSWORD")] password: Option,