fix(password): update password handling for archives

Refactor password handling in archive functions to use &[u8] instead of impl AsRef<[u8]>. Include better error reporting for invalid UTF-8 passwords in 7z archives.
This commit is contained in:
ttyS3 2024-09-06 13:50:00 +00:00 committed by João Marcos
parent d4e252a732
commit 2dad11d0ba
8 changed files with 31 additions and 32 deletions

View File

@ -11,13 +11,11 @@ use crate::{error::Error, list::FileInArchive, utils::logger::info};
pub fn unpack_archive(
archive_path: &Path,
output_folder: &Path,
password: Option<impl AsRef<[u8]>>,
password: Option<&[u8]>,
quiet: bool,
) -> crate::Result<usize> {
assert!(output_folder.read_dir().expect("dir exists").count() == 0);
let password = password.as_ref().map(|p| p.as_ref());
let archive = match password {
Some(password) => Archive::with_password(archive_path, password),
None => Archive::new(archive_path),
@ -49,9 +47,8 @@ pub fn unpack_archive(
/// List contents of `archive_path`, returning a vector of archive entries
pub fn list_archive(
archive_path: &Path,
password: Option<impl AsRef<[u8]>>,
password: Option<&[u8]>,
) -> impl Iterator<Item = crate::Result<FileInArchive>> {
let password = password.as_ref().map(|p| p.as_ref());
let archive = match password {
Some(password) => Archive::with_password(archive_path, password),
None => Archive::new(archive_path),

View File

@ -20,6 +20,7 @@ use crate::{
Bytes, EscapedPathDisplay, FileVisibilityPolicy,
},
};
use crate::error::Error;
pub fn compress_sevenz<W>(
files: &[PathBuf],
@ -102,7 +103,7 @@ where
pub fn decompress_sevenz<R>(
reader: R,
output_path: &Path,
password: Option<impl AsRef<[u8]>>,
password: Option<&[u8]>,
quiet: bool,
) -> crate::Result<usize>
where
@ -161,17 +162,17 @@ where
Ok(true)
};
let password = password.as_ref().map(|p| p.as_ref());
match password {
Some(password) => sevenz_rust::decompress_with_extract_fn_and_password(
reader,
output_path,
sevenz_rust::Password::from(password.to_str().unwrap()),
sevenz_rust::Password::from(password.to_str().map_err(|_| {
Error::InvalidPassword("7z requires that all passwords are valid UTF-8")
})?),
entry_extract_fn,
)?,
None => sevenz_rust::decompress_with_extract_fn(reader, output_path, entry_extract_fn)?,
};
}
Ok(count)
}
@ -179,10 +180,9 @@ where
/// List contents of `archive_path`, returning a vector of archive entries
pub fn list_archive(
archive_path: &Path,
password: Option<impl AsRef<[u8]>>,
password: Option<&[u8]>,
) -> impl Iterator<Item = crate::Result<FileInArchive>> {
let reader = fs::File::open(archive_path).unwrap();
let password = password.as_ref().map(|p| p.as_ref());
let mut files = Vec::new();
@ -195,15 +195,16 @@ pub fn list_archive(
};
match password {
Some(password) => sevenz_rust::decompress_with_extract_fn_and_password(
reader,
".",
sevenz_rust::Password::from(password.to_str().unwrap()),
entry_extract_fn,
)
.unwrap(),
Some(password) => {
sevenz_rust::decompress_with_extract_fn_and_password(
reader,
".",
sevenz_rust::Password::from(password.to_str().unwrap()),
entry_extract_fn,
).unwrap()
},
None => sevenz_rust::decompress_with_extract_fn(reader, ".", entry_extract_fn).unwrap(),
};
}
files.into_iter()
}

View File

@ -32,7 +32,7 @@ use crate::{
pub fn unpack_archive<R>(
mut archive: ZipArchive<R>,
output_folder: &Path,
password: Option<impl AsRef<[u8]>>,
password: Option<&[u8]>,
quiet: bool,
) -> crate::Result<usize>
where
@ -42,10 +42,8 @@ where
let mut unpacked_files = 0;
let password = password.as_ref().map(|p| p.as_ref().to_owned());
for idx in 0..archive.len() {
let mut file = match password.clone() {
let mut file = match password {
Some(password) => archive
.by_index_decrypt(idx, password.to_owned().as_bytes())
.unwrap()
@ -108,7 +106,7 @@ where
/// List contents of `archive`, returning a vector of archive entries
pub fn list_archive<R>(
mut archive: ZipArchive<R>,
password: Option<impl AsRef<[u8]>>,
password: Option<&[u8]>,
) -> impl Iterator<Item = crate::Result<FileInArchive>>
where
R: Read + Seek + Send + 'static,
@ -122,7 +120,7 @@ where
}
}
let password = password.as_ref().map(|p| p.as_ref().to_owned());
let password = password.map(|p| p.to_owned());
let (tx, rx) = mpsc::channel();
thread::spawn(move || {

View File

@ -43,7 +43,7 @@ pub struct CliArgs {
/// decompress or list with password
#[arg(short = 'p', long = "password", global = true)]
pub password: Option<String>,
pub password: Option<OsString>,
// Ouch and claps subcommands
#[command(subcommand)]

View File

@ -36,7 +36,7 @@ pub fn decompress_file(
output_file_path: PathBuf,
question_policy: QuestionPolicy,
quiet: bool,
password: Option<&str>,
password: Option<&[u8]>,
) -> crate::Result<()> {
assert!(output_dir.exists());
let input_is_stdin = is_path_stdin(input_file_path);

View File

@ -21,7 +21,7 @@ pub fn list_archive_contents(
formats: Vec<CompressionFormat>,
list_options: ListOptions,
question_policy: QuestionPolicy,
password: Option<&str>,
password: Option<&[u8]>,
) -> crate::Result<()> {
let reader = fs::File::open(archive_path)?;

View File

@ -5,7 +5,7 @@ mod decompress;
mod list;
use std::{ops::ControlFlow, path::PathBuf};
use std::os::unix::prelude::OsStrExt;
use rayon::prelude::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
use utils::colors;
@ -188,7 +188,7 @@ pub fn run(
output_file_path,
question_policy,
args.quiet,
args.password.as_deref(),
args.password.as_deref().map(|str|str.as_bytes()),
)
})
}
@ -227,7 +227,7 @@ pub fn run(
formats,
list_options,
question_policy,
args.password.as_deref(),
args.password.as_deref().map(|str|str.as_bytes()),
)?;
}

View File

@ -39,6 +39,8 @@ pub enum Error {
/// Recognised but unsupported format
// currently only RAR when built without the `unrar` feature
UnsupportedFormat { reason: String },
/// Invalid password provided
InvalidPassword(&'static str),
}
/// Alias to std's Result with ouch's Error
@ -148,6 +150,7 @@ impl fmt::Display for Error {
Error::UnsupportedFormat { reason } => {
FinalError::with_title("Recognised but unsupported format").detail(reason.clone())
}
Error::InvalidPassword(reason) => FinalError::with_title("Invalid password").detail(*reason),
};
write!(f, "{err}")