mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-05 02:55:31 +00:00
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:
parent
d4e252a732
commit
2dad11d0ba
@ -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),
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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 || {
|
||||
|
@ -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)]
|
||||
|
@ -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);
|
||||
|
@ -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)?;
|
||||
|
||||
|
@ -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()),
|
||||
)?;
|
||||
}
|
||||
|
||||
|
@ -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}")
|
||||
|
Loading…
x
Reference in New Issue
Block a user