use std::path::PathBuf;
use std::sync::Arc;
#[derive(Clone)]
pub struct RarPasswordVerifier {
archive_path: Arc<PathBuf>,
file_name: String,
expected_crc: u32,
original_size: u64,
}
unsafe impl Send for RarPasswordVerifier {}
unsafe impl Sync for RarPasswordVerifier {}
impl RarPasswordVerifier {
pub fn new(archive_path: PathBuf, file_name: String, expected_crc: u32, original_size: u64) -> Self {
Self {
archive_path: Arc::new(archive_path),
file_name,
expected_crc,
original_size,
}
}
pub fn entry_name(&self) -> &str {
&self.file_name
}
pub fn original_size(&self) -> u64 {
self.original_size
}
pub fn verify(&self, password: &str) -> bool {
let archive = match unrar::Archive::with_password(&*self.archive_path, password).open_for_processing() {
Ok(a) => a,
Err(_) => return false,
};
let mut current = archive;
loop {
match current.read_header() {
Ok(Some(header_cursor)) => {
let entry_name = header_cursor.entry().filename.to_string_lossy().to_string();
if entry_name == self.file_name {
match header_cursor.read() {
Ok((data, _)) => {
if data.len() != self.original_size as usize {
return false;
}
let crc = crc32fast::hash(&data);
return crc == self.expected_crc;
}
Err(_) => return false,
}
} else {
match header_cursor.skip() {
Ok(next) => current = next,
Err(_) => return false,
}
}
}
Ok(None) => return false, Err(_) => return false,
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_verifier_is_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<RarPasswordVerifier>();
}
}