use std::io::{Cursor, Read};
use std::sync::Arc;
#[derive(Clone)]
pub struct ZipPasswordVerifier {
archive_data: Arc<[u8]>,
file_index: usize,
expected_crc: u32,
original_size: u64,
entry_name: String,
}
unsafe impl Send for ZipPasswordVerifier {}
unsafe impl Sync for ZipPasswordVerifier {}
impl ZipPasswordVerifier {
pub fn new(archive_data: Vec<u8>, file_index: usize, expected_crc: u32, original_size: u64, entry_name: String) -> Self {
Self {
archive_data: Arc::from(archive_data.into_boxed_slice()),
file_index,
expected_crc,
original_size,
entry_name,
}
}
pub fn entry_name(&self) -> &str {
&self.entry_name
}
pub fn original_size(&self) -> u64 {
self.original_size
}
pub fn verify(&self, password: &str) -> bool {
let cursor = Cursor::new(&*self.archive_data);
let mut archive = match zip::ZipArchive::new(cursor) {
Ok(a) => a,
Err(_) => return false,
};
let mut file = match archive.by_index_decrypt(self.file_index, password.as_bytes()) {
Ok(f) => f,
Err(_) => return false,
};
let mut data = Vec::with_capacity(self.original_size as usize);
if file.read_to_end(&mut data).is_err() {
return false;
}
if data.len() != self.original_size as usize {
return false;
}
let crc = crc32fast::hash(&data);
crc == self.expected_crc
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_verifier_is_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<ZipPasswordVerifier>();
}
}