mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-06 19:45:29 +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(
|
pub fn unpack_archive(
|
||||||
archive_path: &Path,
|
archive_path: &Path,
|
||||||
output_folder: &Path,
|
output_folder: &Path,
|
||||||
password: Option<impl AsRef<[u8]>>,
|
password: Option<&[u8]>,
|
||||||
quiet: bool,
|
quiet: bool,
|
||||||
) -> crate::Result<usize> {
|
) -> crate::Result<usize> {
|
||||||
assert!(output_folder.read_dir().expect("dir exists").count() == 0);
|
assert!(output_folder.read_dir().expect("dir exists").count() == 0);
|
||||||
|
|
||||||
let password = password.as_ref().map(|p| p.as_ref());
|
|
||||||
|
|
||||||
let archive = match password {
|
let archive = match password {
|
||||||
Some(password) => Archive::with_password(archive_path, password),
|
Some(password) => Archive::with_password(archive_path, password),
|
||||||
None => Archive::new(archive_path),
|
None => Archive::new(archive_path),
|
||||||
@ -49,9 +47,8 @@ pub fn unpack_archive(
|
|||||||
/// List contents of `archive_path`, returning a vector of archive entries
|
/// List contents of `archive_path`, returning a vector of archive entries
|
||||||
pub fn list_archive(
|
pub fn list_archive(
|
||||||
archive_path: &Path,
|
archive_path: &Path,
|
||||||
password: Option<impl AsRef<[u8]>>,
|
password: Option<&[u8]>,
|
||||||
) -> impl Iterator<Item = crate::Result<FileInArchive>> {
|
) -> impl Iterator<Item = crate::Result<FileInArchive>> {
|
||||||
let password = password.as_ref().map(|p| p.as_ref());
|
|
||||||
let archive = match password {
|
let archive = match password {
|
||||||
Some(password) => Archive::with_password(archive_path, password),
|
Some(password) => Archive::with_password(archive_path, password),
|
||||||
None => Archive::new(archive_path),
|
None => Archive::new(archive_path),
|
||||||
|
@ -20,6 +20,7 @@ use crate::{
|
|||||||
Bytes, EscapedPathDisplay, FileVisibilityPolicy,
|
Bytes, EscapedPathDisplay, FileVisibilityPolicy,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use crate::error::Error;
|
||||||
|
|
||||||
pub fn compress_sevenz<W>(
|
pub fn compress_sevenz<W>(
|
||||||
files: &[PathBuf],
|
files: &[PathBuf],
|
||||||
@ -102,7 +103,7 @@ where
|
|||||||
pub fn decompress_sevenz<R>(
|
pub fn decompress_sevenz<R>(
|
||||||
reader: R,
|
reader: R,
|
||||||
output_path: &Path,
|
output_path: &Path,
|
||||||
password: Option<impl AsRef<[u8]>>,
|
password: Option<&[u8]>,
|
||||||
quiet: bool,
|
quiet: bool,
|
||||||
) -> crate::Result<usize>
|
) -> crate::Result<usize>
|
||||||
where
|
where
|
||||||
@ -161,17 +162,17 @@ where
|
|||||||
Ok(true)
|
Ok(true)
|
||||||
};
|
};
|
||||||
|
|
||||||
let password = password.as_ref().map(|p| p.as_ref());
|
|
||||||
|
|
||||||
match password {
|
match password {
|
||||||
Some(password) => sevenz_rust::decompress_with_extract_fn_and_password(
|
Some(password) => sevenz_rust::decompress_with_extract_fn_and_password(
|
||||||
reader,
|
reader,
|
||||||
output_path,
|
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,
|
entry_extract_fn,
|
||||||
)?,
|
)?,
|
||||||
None => sevenz_rust::decompress_with_extract_fn(reader, output_path, entry_extract_fn)?,
|
None => sevenz_rust::decompress_with_extract_fn(reader, output_path, entry_extract_fn)?,
|
||||||
};
|
}
|
||||||
|
|
||||||
Ok(count)
|
Ok(count)
|
||||||
}
|
}
|
||||||
@ -179,10 +180,9 @@ where
|
|||||||
/// List contents of `archive_path`, returning a vector of archive entries
|
/// List contents of `archive_path`, returning a vector of archive entries
|
||||||
pub fn list_archive(
|
pub fn list_archive(
|
||||||
archive_path: &Path,
|
archive_path: &Path,
|
||||||
password: Option<impl AsRef<[u8]>>,
|
password: Option<&[u8]>,
|
||||||
) -> impl Iterator<Item = crate::Result<FileInArchive>> {
|
) -> impl Iterator<Item = crate::Result<FileInArchive>> {
|
||||||
let reader = fs::File::open(archive_path).unwrap();
|
let reader = fs::File::open(archive_path).unwrap();
|
||||||
let password = password.as_ref().map(|p| p.as_ref());
|
|
||||||
|
|
||||||
let mut files = Vec::new();
|
let mut files = Vec::new();
|
||||||
|
|
||||||
@ -195,15 +195,16 @@ pub fn list_archive(
|
|||||||
};
|
};
|
||||||
|
|
||||||
match password {
|
match password {
|
||||||
Some(password) => sevenz_rust::decompress_with_extract_fn_and_password(
|
Some(password) => {
|
||||||
|
sevenz_rust::decompress_with_extract_fn_and_password(
|
||||||
reader,
|
reader,
|
||||||
".",
|
".",
|
||||||
sevenz_rust::Password::from(password.to_str().unwrap()),
|
sevenz_rust::Password::from(password.to_str().unwrap()),
|
||||||
entry_extract_fn,
|
entry_extract_fn,
|
||||||
)
|
).unwrap()
|
||||||
.unwrap(),
|
},
|
||||||
None => sevenz_rust::decompress_with_extract_fn(reader, ".", entry_extract_fn).unwrap(),
|
None => sevenz_rust::decompress_with_extract_fn(reader, ".", entry_extract_fn).unwrap(),
|
||||||
};
|
}
|
||||||
|
|
||||||
files.into_iter()
|
files.into_iter()
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ use crate::{
|
|||||||
pub fn unpack_archive<R>(
|
pub fn unpack_archive<R>(
|
||||||
mut archive: ZipArchive<R>,
|
mut archive: ZipArchive<R>,
|
||||||
output_folder: &Path,
|
output_folder: &Path,
|
||||||
password: Option<impl AsRef<[u8]>>,
|
password: Option<&[u8]>,
|
||||||
quiet: bool,
|
quiet: bool,
|
||||||
) -> crate::Result<usize>
|
) -> crate::Result<usize>
|
||||||
where
|
where
|
||||||
@ -42,10 +42,8 @@ where
|
|||||||
|
|
||||||
let mut unpacked_files = 0;
|
let mut unpacked_files = 0;
|
||||||
|
|
||||||
let password = password.as_ref().map(|p| p.as_ref().to_owned());
|
|
||||||
|
|
||||||
for idx in 0..archive.len() {
|
for idx in 0..archive.len() {
|
||||||
let mut file = match password.clone() {
|
let mut file = match password {
|
||||||
Some(password) => archive
|
Some(password) => archive
|
||||||
.by_index_decrypt(idx, password.to_owned().as_bytes())
|
.by_index_decrypt(idx, password.to_owned().as_bytes())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -108,7 +106,7 @@ where
|
|||||||
/// List contents of `archive`, returning a vector of archive entries
|
/// List contents of `archive`, returning a vector of archive entries
|
||||||
pub fn list_archive<R>(
|
pub fn list_archive<R>(
|
||||||
mut archive: ZipArchive<R>,
|
mut archive: ZipArchive<R>,
|
||||||
password: Option<impl AsRef<[u8]>>,
|
password: Option<&[u8]>,
|
||||||
) -> impl Iterator<Item = crate::Result<FileInArchive>>
|
) -> impl Iterator<Item = crate::Result<FileInArchive>>
|
||||||
where
|
where
|
||||||
R: Read + Seek + Send + 'static,
|
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();
|
let (tx, rx) = mpsc::channel();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
|
@ -43,7 +43,7 @@ pub struct CliArgs {
|
|||||||
|
|
||||||
/// decompress or list with password
|
/// decompress or list with password
|
||||||
#[arg(short = 'p', long = "password", global = true)]
|
#[arg(short = 'p', long = "password", global = true)]
|
||||||
pub password: Option<String>,
|
pub password: Option<OsString>,
|
||||||
|
|
||||||
// Ouch and claps subcommands
|
// Ouch and claps subcommands
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
|
@ -36,7 +36,7 @@ pub fn decompress_file(
|
|||||||
output_file_path: PathBuf,
|
output_file_path: PathBuf,
|
||||||
question_policy: QuestionPolicy,
|
question_policy: QuestionPolicy,
|
||||||
quiet: bool,
|
quiet: bool,
|
||||||
password: Option<&str>,
|
password: Option<&[u8]>,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
assert!(output_dir.exists());
|
assert!(output_dir.exists());
|
||||||
let input_is_stdin = is_path_stdin(input_file_path);
|
let input_is_stdin = is_path_stdin(input_file_path);
|
||||||
|
@ -21,7 +21,7 @@ pub fn list_archive_contents(
|
|||||||
formats: Vec<CompressionFormat>,
|
formats: Vec<CompressionFormat>,
|
||||||
list_options: ListOptions,
|
list_options: ListOptions,
|
||||||
question_policy: QuestionPolicy,
|
question_policy: QuestionPolicy,
|
||||||
password: Option<&str>,
|
password: Option<&[u8]>,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
let reader = fs::File::open(archive_path)?;
|
let reader = fs::File::open(archive_path)?;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ mod decompress;
|
|||||||
mod list;
|
mod list;
|
||||||
|
|
||||||
use std::{ops::ControlFlow, path::PathBuf};
|
use std::{ops::ControlFlow, path::PathBuf};
|
||||||
|
use std::os::unix::prelude::OsStrExt;
|
||||||
use rayon::prelude::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
use rayon::prelude::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
||||||
use utils::colors;
|
use utils::colors;
|
||||||
|
|
||||||
@ -188,7 +188,7 @@ pub fn run(
|
|||||||
output_file_path,
|
output_file_path,
|
||||||
question_policy,
|
question_policy,
|
||||||
args.quiet,
|
args.quiet,
|
||||||
args.password.as_deref(),
|
args.password.as_deref().map(|str|str.as_bytes()),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -227,7 +227,7 @@ pub fn run(
|
|||||||
formats,
|
formats,
|
||||||
list_options,
|
list_options,
|
||||||
question_policy,
|
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
|
/// Recognised but unsupported format
|
||||||
// currently only RAR when built without the `unrar` feature
|
// currently only RAR when built without the `unrar` feature
|
||||||
UnsupportedFormat { reason: String },
|
UnsupportedFormat { reason: String },
|
||||||
|
/// Invalid password provided
|
||||||
|
InvalidPassword(&'static str),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Alias to std's Result with ouch's Error
|
/// Alias to std's Result with ouch's Error
|
||||||
@ -148,6 +150,7 @@ impl fmt::Display for Error {
|
|||||||
Error::UnsupportedFormat { reason } => {
|
Error::UnsupportedFormat { reason } => {
|
||||||
FinalError::with_title("Recognised but unsupported format").detail(reason.clone())
|
FinalError::with_title("Recognised but unsupported format").detail(reason.clone())
|
||||||
}
|
}
|
||||||
|
Error::InvalidPassword(reason) => FinalError::with_title("Invalid password").detail(*reason),
|
||||||
};
|
};
|
||||||
|
|
||||||
write!(f, "{err}")
|
write!(f, "{err}")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user