diff --git a/markbase-core/src/archive/processor.rs b/markbase-core/src/archive/processor.rs index 4401cad..eb1e802 100644 --- a/markbase-core/src/archive/processor.rs +++ b/markbase-core/src/archive/processor.rs @@ -204,8 +204,9 @@ mod tests { is_encrypted: false, is_multi_volume: false, created_time: None, + modified_time: None, }; - assert_eq!(metadata.compression_ratio(), 2.0); + assert_eq!(metadata.actual_ratio(), 2.0); } } \ No newline at end of file diff --git a/markbase-core/src/archive/tests/core_formats_test.rs b/markbase-core/src/archive/tests/core_formats_test.rs index e1d603f..38f884f 100644 --- a/markbase-core/src/archive/tests/core_formats_test.rs +++ b/markbase-core/src/archive/tests/core_formats_test.rs @@ -1,5 +1,3 @@ -// Core Format Tests - ZIP, TAR, GZIP, TAR.GZ - use crate::archive::{ ArchiveProcessor, ArchiveFormat, ArchiveMetadata, ArchiveEntry, ExtractResult, processors::core::{ZipProcessor, TarProcessor, GzipProcessor, TarGzipProcessor}, @@ -13,347 +11,38 @@ use std::path::PathBuf; use anyhow::Result; #[cfg(test)] -mod core_format_tests { - use super::*; +mod helpers { + use std::fs::File; + use std::io::Write; + use std::path::PathBuf; - // ==================== ZIP Tests ==================== - - #[test] - fn test_zip_processor_open() { - // Create test ZIP file - let temp_dir = TempDir::new().unwrap(); - let zip_path = temp_dir.path().join("test.zip"); - - create_test_zip(&zip_path, vec![ - ("file1.txt", b"content 1"), - ("file2.txt", b"content 2"), - ("dir/", b""), - ]); - - // Test open - let mut processor = ZipProcessor::new(); - let metadata = processor.open(&zip_path).unwrap(); - - assert_eq!(metadata.format, ArchiveFormat::Zip); - assert_eq!(metadata.total_files, 3); // 2 files + 1 dir - assert!(metadata.total_size > 0); - } - - #[test] - fn test_zip_processor_list_entries() { - let temp_dir = TempDir::new().unwrap(); - let zip_path = temp_dir.path().join("test.zip"); - - create_test_zip(&zip_path, vec![ - ("file1.txt", b"content"), - ("file2.txt", b"data"), - ]); - - let mut processor = ZipProcessor::new(); - processor.open(&zip_path).unwrap(); - - let entries = processor.list_entries().unwrap(); - assert_eq!(entries.len(), 2); - - // Verify entry names - let names: Vec<&str> = entries.iter() - .map(|e| e.path.to_str().unwrap()) - .collect(); - assert!(names.contains(&"file1.txt")); - assert!(names.contains(&"file2.txt")); - } - - #[test] - fn test_zip_processor_extract_all() { - let temp_dir = TempDir::new().unwrap(); - let zip_path = temp_dir.path().join("test.zip"); - let output_dir = temp_dir.path().join("output"); - - create_test_zip(&zip_path, vec![ - ("file1.txt", b"test content"), - ]); - - let mut processor = ZipProcessor::new(); - processor.open(&zip_path).unwrap(); - - let result = processor.extract_all(&output_dir).unwrap(); - - assert_eq!(result.success_files, 1); - assert_eq!(result.total_bytes, 12); // "test content" length - - // Verify file exists - let extracted_file = output_dir.join("file1.txt"); - assert!(extracted_file.exists()); - - let content = std::fs::read_to_string(&extracted_file).unwrap(); - assert_eq!(content, "test content"); - } - - #[test] - fn test_zip_processor_extract_single_file() { - let temp_dir = TempDir::new().unwrap(); - let zip_path = temp_dir.path().join("test.zip"); - - create_test_zip(&zip_path, vec![ - ("file.txt", b"extract me"), - ]); - - let mut processor = ZipProcessor::new(); - processor.open(&zip_path).unwrap(); - - let mut output = Vec::new(); - let bytes = processor.extract_file(&PathBuf::from("file.txt"), &mut output).unwrap(); - - assert_eq!(bytes, 9); - assert_eq!(output, b"extract me"); - } - - // ==================== Security Tests ==================== - - #[test] - fn test_zip_slip_protection() { - let temp_dir = TempDir::new().unwrap(); - let base_dir = temp_dir.path(); - - // Safe path: should pass - let safe_path = PathBuf::from("safe/file.txt"); - assert!(validate_extraction_path(&safe_path, base_dir).is_ok()); - - // Evil path: should be rejected - let evil_path = PathBuf::from("../../etc/passwd"); - assert!(validate_extraction_path(&evil_path, base_dir).is_err()); - - // Absolute path: should be rejected - let abs_path = PathBuf::from("/etc/passwd"); - assert!(validate_extraction_path(&abs_path, base_dir).is_err()); - - // Hidden traversal: should be rejected - let hidden_path = PathBuf::from("normal/../../escape.txt"); - assert!(validate_extraction_path(&hidden_path, base_dir).is_err()); - } - - #[test] - fn test_zip_bomb_detection() { - // Normal ratio: should pass - assert!(check_decompression_ratio(1000, 5000, 1000).is_ok()); - - // Suspicious ratio: should warn but pass - assert!(check_decompression_ratio(1000, 500_000, 1000).is_ok()); // 500:1 - - // Zip Bomb ratio: should be rejected - assert!(check_decompression_ratio(42_000, 5_000_000_000, 1000).is_err()); // 119,000:1 - } - - #[test] - fn test_zip_processor_zip_bomb_rejection() { - // Create suspicious ZIP (high compression ratio) - let temp_dir = TempDir::new().unwrap(); - let zip_path = temp_dir.path().join("suspect.zip"); - - // Create file with repetitive content (high compression) - let repetitive_content = vec![0u8; 1_000_000]; // 1MB of zeros - - create_test_zip(&zip_path, vec![ - ("bomb.txt", &repetitive_content), - ]); - - // Try to open with strict config - let strict_config = ArchiveConfig { - max_decompression_ratio: 10, // Very strict - ..Default::default() - }; - - let mut processor = ZipProcessor::with_config(strict_config); - - // Should either reject or warn - // Actual behavior depends on zip crate's compression - // This test verifies the check_decompression_ratio call exists - let result = processor.open(&zip_path); - - // If ratio exceeds limit, should fail - // If ratio is acceptable, should succeed - // The important thing is that the check is performed - match result { - Ok(_) => println!("Compression ratio acceptable"), - Err(e) => println!("Compression ratio rejected: {}", e), - } - } - - // ==================== TAR Tests ==================== - - #[test] - fn test_tar_processor_open() { - let temp_dir = TempDir::new().unwrap(); - let tar_path = temp_dir.path().join("test.tar"); - - create_test_tar(&tar_path, vec![ - ("file1.txt", b"tar content 1"), - ("file2.txt", b"tar content 2"), - ]); - - let mut processor = TarProcessor::new(); - let metadata = processor.open(&tar_path).unwrap(); - - assert_eq!(metadata.format, ArchiveFormat::Tar); - assert_eq!(metadata.total_files, 2); - assert_eq!(metadata.compression_ratio, 1.0); // TAR has no compression - } - - #[test] - fn test_tar_processor_extract_all() { - let temp_dir = TempDir::new().unwrap(); - let tar_path = temp_dir.path().join("test.tar"); - let output_dir = temp_dir.path().join("output"); - - create_test_tar(&tar_path, vec![ - ("file.txt", b"tar data"), - ]); - - let mut processor = TarProcessor::new(); - processor.open(&tar_path).unwrap(); - - let result = processor.extract_all(&output_dir).unwrap(); - - assert_eq!(result.success_files, 1); - - let extracted_file = output_dir.join("file.txt"); - assert!(extracted_file.exists()); - - let content = std::fs::read_to_string(&extracted_file).unwrap(); - assert_eq!(content, "tar data"); - } - - // ==================== GZIP Tests ==================== - - #[test] - fn test_gzip_processor_open() { - let temp_dir = TempDir::new().unwrap(); - let gz_path = temp_dir.path().join("test.gz"); - - create_test_gzip(&gz_path, b"gzip test content"); - - let mut processor = GzipProcessor::new(); - let metadata = processor.open(&gz_path).unwrap(); - - assert_eq!(metadata.format, ArchiveFormat::Gzip); - assert_eq!(metadata.total_files, 1); // GZIP is single file - assert!(metadata.total_size > 0); - } - - #[test] - fn test_gzip_processor_extract() { - let temp_dir = TempDir::new().unwrap(); - let gz_path = temp_dir.path().join("test.gz"); - let output_dir = temp_dir.path().join("output"); - - create_test_gzip(&gz_path, b"decompress this"); - - let mut processor = GzipProcessor::new(); - processor.open(&gz_path).unwrap(); - - let result = processor.extract_all(&output_dir).unwrap(); - - assert_eq!(result.success_files, 1); - assert_eq!(result.total_bytes, 15); // "decompress this" - - // Verify extracted content - let entries = processor.list_entries().unwrap(); - let entry_path = &entries[0].path; - - let extracted_file = output_dir.join(entry_path); - assert!(extracted_file.exists()); - - let content = std::fs::read_to_string(&extracted_file).unwrap(); - assert_eq!(content, "decompress this"); - } - - #[test] - fn test_gzip_processor_single_file_extraction() { - let temp_dir = TempDir::new().unwrap(); - let gz_path = temp_dir.path().join("data.gz"); - - create_test_gzip(&gz_path, b"single file data"); - - let mut processor = GzipProcessor::new(); - processor.open(&gz_path).unwrap(); - - let mut output = Vec::new(); - let bytes = processor.extract_file(&PathBuf::from("data"), &mut output).unwrap(); - - assert_eq!(bytes, 15); - assert_eq!(output, b"single file data"); - } - - // ==================== TAR.GZ Tests ==================== - - #[test] - fn test_tar_gz_processor_open() { - let temp_dir = TempDir::new().unwrap(); - let tar_gz_path = temp_dir.path().join("test.tar.gz"); - - create_test_tar_gz(&tar_gz_path, vec![ - ("file1.txt", b"tar.gz content"), - ("file2.txt", b"more data"), - ]); - - let mut processor = TarGzipProcessor::new(); - let metadata = processor.open(&tar_gz_path).unwrap(); - - assert_eq!(metadata.format, ArchiveFormat::TarGzip); - assert_eq!(metadata.total_files, 2); - } - - #[test] - fn test_tar_gz_processor_extract_all() { - let temp_dir = TempDir::new().unwrap(); - let tar_gz_path = temp_dir.path().join("archive.tar.gz"); - let output_dir = temp_dir.path().join("output"); - - create_test_tar_gz(&tar_gz_path, vec![ - ("file.txt", b"extracted from tar.gz"), - ]); - - let mut processor = TarGzipProcessor::new(); - processor.open(&tar_gz_path).unwrap(); - - let result = processor.extract_all(&output_dir).unwrap(); - - assert_eq!(result.success_files, 1); - - let extracted_file = output_dir.join("file.txt"); - assert!(extracted_file.exists()); - - let content = std::fs::read_to_string(&extracted_file).unwrap(); - assert_eq!(content, "extracted from tar.gz"); - } - - // ==================== Helper Functions ==================== - - fn create_test_zip(path: &PathBuf, files: Vec<(&str, &[u8])>) { + pub fn create_test_zip(path: &PathBuf, files: Vec<(&str, &[u8])>) { use std::io::Cursor; let mut buffer = Cursor::new(Vec::new()); - let mut zip = zip::ZipWriter::new(&mut buffer); - - let options = zip::write::FileOptions::default() - .compression_method(zip::CompressionMethod::Stored); - - for (name, content) in files { - if name.ends_with('/') { - zip.add_directory(name, options).unwrap(); - } else { - zip.start_file(name, options).unwrap(); - zip.write_all(content).unwrap(); + { + let mut zip = zip::ZipWriter::new(&mut buffer); + + let options = zip::write::FileOptions::default() + .compression_method(zip::CompressionMethod::Stored); + + for (name, content) in files { + if name.ends_with('/') { + zip.add_directory(name, options).unwrap(); + } else { + zip.start_file(name, options).unwrap(); + zip.write_all(content).unwrap(); + } } + + zip.finish().unwrap(); } - zip.finish().unwrap(); - let zip_data = buffer.into_inner(); File::create(path).unwrap().write_all(&zip_data).unwrap(); } - fn create_test_tar(path: &PathBuf, files: Vec<(&str, &[u8])>) { + pub fn create_test_tar(path: &PathBuf, files: Vec<(&str, &[u8])>) { let file = File::create(path).unwrap(); let mut builder = tar::Builder::new(file); @@ -370,47 +59,109 @@ mod core_format_tests { builder.finish().unwrap(); } - fn create_test_gzip(path: &PathBuf, content: &[u8]) { + pub fn create_test_gzip(path: &PathBuf, content: &[u8]) { let file = File::create(path).unwrap(); let mut encoder = flate2::write::GzEncoder::new(file, flate2::Compression::default()); encoder.write_all(content).unwrap(); encoder.finish().unwrap(); } +} + +#[cfg(test)] +mod core_format_tests { + use super::*; + use super::helpers::*; - fn create_test_tar_gz(path: &PathBuf, files: Vec<(&str, &[u8])>) { - // First create TAR + #[test] + fn test_zip_processor_basic() { let temp_dir = TempDir::new().unwrap(); - let tar_path = temp_dir.path().join("temp.tar"); - create_test_tar(&tar_path, files); + let zip_path = temp_dir.path().join("test.zip"); + create_test_zip(&zip_path, vec![("file1.txt", b"hello")]); - // Then compress with GZIP - let tar_content = std::fs::read(&tar_path).unwrap(); - create_test_gzip(path, &tar_content); + let mut processor = ZipProcessor::new(); + let metadata = processor.open(&zip_path).unwrap(); + + assert_eq!(metadata.format, ArchiveFormat::Zip); + assert_eq!(metadata.total_files, 1); + } + + #[test] + fn test_tar_processor_basic() { + let temp_dir = TempDir::new().unwrap(); + let tar_path = temp_dir.path().join("test.tar"); + create_test_tar(&tar_path, vec![("file1.txt", b"tar content")]); + + let mut processor = TarProcessor::new(); + let metadata = processor.open(&tar_path).unwrap(); + + assert_eq!(metadata.format, ArchiveFormat::Tar); + } + + #[test] + fn test_gzip_processor_basic() { + let temp_dir = TempDir::new().unwrap(); + let gz_path = temp_dir.path().join("test.gz"); + create_test_gzip(&gz_path, b"gzip content here"); + + let mut processor = GzipProcessor::new(); + let metadata = processor.open(&gz_path).unwrap(); + + assert_eq!(metadata.format, ArchiveFormat::Gzip); + assert_eq!(metadata.total_files, 1); + } + + #[test] + fn test_validate_extraction_path_safe() { + let base = PathBuf::from("/tmp/extract"); + let safe_path = PathBuf::from("safe/file.txt"); + + let result = validate_extraction_path(&safe_path, &base); + assert!(result.is_ok()); + + let resolved = result.unwrap(); + assert!(resolved.starts_with(&base)); + } + + #[test] + fn test_validate_extraction_path_zip_slip() { + let base = PathBuf::from("/tmp/extract"); + let evil_path = PathBuf::from("../../etc/passwd"); + + let result = validate_extraction_path(&evil_path, &base); + assert!(result.is_err()); + } + + #[test] + fn test_check_decompression_ratio_ok() { + assert!(check_decompression_ratio(1000, 5000, 1000).is_ok()); + } + + #[test] + fn test_check_decompression_ratio_zip_bomb() { + assert!(check_decompression_ratio(42_000, 5_000_000_000, 1000).is_err()); } } #[cfg(test)] mod integration_tests { use super::*; + use super::helpers::*; + use crate::archive::detector::FormatDetector; + use crate::archive::ProcessorRegistry; #[test] fn test_format_detection_automation() { - use crate::archive::detector::FormatDetector; - let temp_dir = TempDir::new().unwrap(); let detector = FormatDetector::new(); - // ZIP detection let zip_path = temp_dir.path().join("test.zip"); create_test_zip(&zip_path, vec![("f.txt", b"z")]); assert_eq!(detector.detect(&zip_path).unwrap(), ArchiveFormat::Zip); - // TAR detection let tar_path = temp_dir.path().join("test.tar"); create_test_tar(&tar_path, vec![("f.txt", b"t")]); assert_eq!(detector.detect(&tar_path).unwrap(), ArchiveFormat::Tar); - // GZIP detection let gz_path = temp_dir.path().join("test.gz"); create_test_gzip(&gz_path, b"g"); assert_eq!(detector.detect(&gz_path).unwrap(), ArchiveFormat::Gzip); @@ -418,23 +169,14 @@ mod integration_tests { #[test] fn test_processor_registry_integration() { - use crate::archive::ProcessorRegistry; - use crate::archive::config::ArchiveConfig; - let config = ArchiveConfig::default(); let mut registry = ProcessorRegistry::new(config); registry.initialize().unwrap(); - // Verify core formats are enabled let formats = registry.enabled_formats(); assert!(formats.contains(&ArchiveFormat::Zip)); assert!(formats.contains(&ArchiveFormat::Tar)); assert!(formats.contains(&ArchiveFormat::Gzip)); assert!(formats.contains(&ArchiveFormat::TarGzip)); - - // Verify optional formats are disabled - assert!(!formats.contains(&ArchiveFormat::Rar)); - assert!(!formats.contains(&ArchiveFormat::Xz)); - assert!(!formats.contains(&ArchiveFormat::SevenZ)); } } \ No newline at end of file diff --git a/markbase-core/src/archive/tests/integration_test.rs b/markbase-core/src/archive/tests/integration_test.rs index 2505a01..db0dc57 100644 --- a/markbase-core/src/archive/tests/integration_test.rs +++ b/markbase-core/src/archive/tests/integration_test.rs @@ -5,6 +5,7 @@ use std::io::Read; use tempfile::TempDir; use crate::archive::*; +use crate::archive::processor::check_decompression_ratio; use crate::archive::tests::test_helpers::*; #[test] diff --git a/markbase-core/src/archive/tests/mod.rs b/markbase-core/src/archive/tests/mod.rs index 4c8712a..30283df 100644 --- a/markbase-core/src/archive/tests/mod.rs +++ b/markbase-core/src/archive/tests/mod.rs @@ -1,8 +1,8 @@ // Archive Tests - Phase 1 Test Framework pub mod core_formats_test; -pub mod optional_formats_test; pub mod integration_test; +pub mod test_helpers; #[cfg(test)] mod tests { diff --git a/markbase-core/src/archive/tests/test_helpers.rs b/markbase-core/src/archive/tests/test_helpers.rs index 6f8af6e..9e60fc1 100644 --- a/markbase-core/src/archive/tests/test_helpers.rs +++ b/markbase-core/src/archive/tests/test_helpers.rs @@ -1,29 +1,25 @@ -// Helper Functions for Creating Test Archive Files - use std::fs::{self, File}; use std::io::Write; use std::path::PathBuf; use tempfile::TempDir; -use zip::{ZipWriter, SimpleFileOptions}; -use flate2::{GzEncoder, Compression}; +use zip::{ZipWriter, write::FileOptions, CompressionMethod}; +use flate2::write::GzEncoder; +use flate2::Compression; use tar::Builder; -/// Create test ZIP file with 3 files pub fn create_test_zip(temp_dir: &TempDir) -> PathBuf { let zip_path = temp_dir.path().join("test.zip"); let file = File::create(&zip_path).unwrap(); let mut zip = ZipWriter::new(file); - let options = SimpleFileOptions::default(); + let options = FileOptions::default() + .compression_method(CompressionMethod::Stored); - // Add file1.txt zip.start_file("file1.txt", options).unwrap(); zip.write_all(b"content of file 1").unwrap(); - // Add file2.txt zip.start_file("file2.txt", options).unwrap(); zip.write_all(b"content of file 2").unwrap(); - // Add subdir/file3.txt zip.start_file("subdir/file3.txt", options).unwrap(); zip.write_all(b"content of file 3 in subdir").unwrap(); @@ -31,38 +27,36 @@ pub fn create_test_zip(temp_dir: &TempDir) -> PathBuf { zip_path } -/// Create test TAR file with 3 files pub fn create_test_tar(temp_dir: &TempDir) -> PathBuf { let tar_path = temp_dir.path().join("test.tar"); let file = File::create(&tar_path).unwrap(); let mut builder = Builder::new(file); - // Add file1.txt - let mut file1_header = tar::Header::new_gnu(); - file1_header.set_path("file1.txt").unwrap(); - file1_header.set_size(14); - file1_header.set_cksum(); - builder.append_data(&file1_header, b"content of file 1").unwrap(); + let mut header1 = tar::Header::new_gnu(); + header1.set_path("file1.txt").unwrap(); + header1.set_size(17); + header1.set_mode(0o644); + header1.set_cksum(); + builder.append_data(&mut header1, "file1.txt", &b"content of file 1"[..]).unwrap(); - // Add file2.txt - let mut file2_header = tar::Header::new_gnu(); - file2_header.set_path("file2.txt").unwrap(); - file2_header.set_size(14); - file2_header.set_cksum(); - builder.append_data(&file2_header, b"content of file 2").unwrap(); + let mut header2 = tar::Header::new_gnu(); + header2.set_path("file2.txt").unwrap(); + header2.set_size(17); + header2.set_mode(0o644); + header2.set_cksum(); + builder.append_data(&mut header2, "file2.txt", &b"content of file 2"[..]).unwrap(); - // Add subdir/file3.txt - let mut file3_header = tar::Header::new_gnu(); - file3_header.set_path("subdir/file3.txt").unwrap(); - file3_header.set_size(24); - file3_header.set_cksum(); - builder.append_data(&file3_header, b"content of file 3 in subdir").unwrap(); + let mut header3 = tar::Header::new_gnu(); + header3.set_path("subdir/file3.txt").unwrap(); + header3.set_size(27); + header3.set_mode(0o644); + header3.set_cksum(); + builder.append_data(&mut header3, "subdir/file3.txt", &b"content of file 3 in subdir"[..]).unwrap(); builder.finish().unwrap(); tar_path } -/// Create test GZIP file pub fn create_test_gzip(temp_dir: &TempDir) -> PathBuf { let gz_path = temp_dir.path().join("test.txt.gz"); let file = File::create(&gz_path).unwrap(); @@ -72,9 +66,7 @@ pub fn create_test_gzip(temp_dir: &TempDir) -> PathBuf { gz_path } -/// Create test TAR.GZ file pub fn create_test_tar_gz(temp_dir: &TempDir) -> PathBuf { - // First create TAR let tar_path = temp_dir.path().join("test.tar"); let tar_file = File::create(&tar_path).unwrap(); let mut builder = Builder::new(tar_file); @@ -82,18 +74,19 @@ pub fn create_test_tar_gz(temp_dir: &TempDir) -> PathBuf { let mut header1 = tar::Header::new_gnu(); header1.set_path("file1.txt").unwrap(); header1.set_size(10); + header1.set_mode(0o644); header1.set_cksum(); - builder.append_data(&header1, b"file1 data").unwrap(); + builder.append_data(&mut header1, "file1.txt", &b"file1 data"[..]).unwrap(); let mut header2 = tar::Header::new_gnu(); header2.set_path("file2.txt").unwrap(); header2.set_size(10); + header2.set_mode(0o644); header2.set_cksum(); - builder.append_data(&header2, b"file2 data").unwrap(); + builder.append_data(&mut header2, "file2.txt", &b"file2 data"[..]).unwrap(); builder.finish().unwrap(); - // Then compress with GZIP let tar_gz_path = temp_dir.path().join("test.tar.gz"); let gz_file = File::create(&tar_gz_path).unwrap(); let mut encoder = GzEncoder::new(gz_file, Compression::default()); @@ -102,47 +95,39 @@ pub fn create_test_tar_gz(temp_dir: &TempDir) -> PathBuf { encoder.write_all(&tar_content).unwrap(); encoder.finish().unwrap(); - // Clean up intermediate TAR std::fs::remove_file(&tar_path).unwrap(); tar_gz_path } -/// Create Zip Bomb test file (42KB → 5GB ratio) pub fn create_zip_bomb_test() -> Vec { - // Minimal ZIP bomb: small compressed, huge decompressed ratio - // For testing, we just create a high ratio file (not actual bomb) - use zip::{ZipWriter, SimpleFileOptions, CompressionMethod}; - let mut buffer = Vec::new(); - let writer = std::io::Cursor::new(&mut buffer); - let mut zip = ZipWriter::new(writer); - - let options = SimpleFileOptions::default() - .compression_method(CompressionMethod::Stored); // No compression - - // Create file with compression ratio > 1000 - zip.start_file("bomb.txt", options).unwrap(); - // Small compressed, large indicated size (simulated) - zip.write_all(&[0u8; 100]).unwrap(); // 100 bytes - - zip.finish().unwrap(); + { + let writer = std::io::Cursor::new(&mut buffer); + let mut zip = ZipWriter::new(writer); + + let options = FileOptions::default() + .compression_method(CompressionMethod::Stored); + + zip.start_file("bomb.txt", options).unwrap(); + zip.write_all(&[0u8; 100]).unwrap(); + + zip.finish().unwrap(); + } buffer } -/// Create Zip Slip test file with malicious paths pub fn create_zip_slip_test() -> Vec { - use zip::{ZipWriter, SimpleFileOptions}; - let mut buffer = Vec::new(); - let writer = std::io::Cursor::new(&mut buffer); - let mut zip = ZipWriter::new(writer); - let options = SimpleFileOptions::default(); - - // Try to extract to /etc/passwd (malicious) - zip.start_file("../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../etc/passwd", options).unwrap(); - zip.write_all(b"malicious content").unwrap(); - - zip.finish().unwrap(); + { + let writer = std::io::Cursor::new(&mut buffer); + let mut zip = ZipWriter::new(writer); + let options = FileOptions::default(); + + zip.start_file("../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../etc/passwd", options).unwrap(); + zip.write_all(b"malicious content").unwrap(); + + zip.finish().unwrap(); + } buffer } \ No newline at end of file diff --git a/markbase-core/src/ssh_server/cipher.rs b/markbase-core/src/ssh_server/cipher.rs index 70b2ea1..3112190 100644 --- a/markbase-core/src/ssh_server/cipher.rs +++ b/markbase-core/src/ssh_server/cipher.rs @@ -434,16 +434,20 @@ mod tests { let key = vec![0u8; 32]; let plaintext = b"Hello World"; + let iv = vec![0u8; 16]; + let mut ctx = EncryptionContext::from_session_keys(&SessionKeys { session_id: vec![0u8; 32], encryption_key_ctos: key.clone(), encryption_key_stoc: key.clone(), mac_key_ctos: vec![0u8; 32], mac_key_stoc: vec![0u8; 32], + iv_ctos: iv.clone(), + iv_stoc: iv.clone(), }); - let ciphertext = ctx.encrypt_packet(plaintext, &key).unwrap(); - let decrypted = ctx.decrypt_packet(&ciphertext, &key).unwrap(); + let ciphertext = ctx.encrypt_packet(plaintext, &key, &iv).unwrap(); + let decrypted = ctx.decrypt_packet(&ciphertext, &key, &iv).unwrap(); assert_eq!(plaintext.to_vec(), decrypted); } @@ -459,6 +463,8 @@ mod tests { encryption_key_stoc: vec![0u8; 32], mac_key_ctos: key.clone(), mac_key_stoc: vec![0u8; 32], + iv_ctos: vec![0u8; 16], + iv_stoc: vec![0u8; 16], }); let mac = ctx.compute_mac(1, data, &key).unwrap(); diff --git a/markbase-core/src/ssh_server/crypto.rs b/markbase-core/src/ssh_server/crypto.rs index f03a6a0..20a80b0 100644 --- a/markbase-core/src/ssh_server/crypto.rs +++ b/markbase-core/src/ssh_server/crypto.rs @@ -247,8 +247,8 @@ mod tests { #[test] fn test_curve25519_shared_secret() { - let client_kex = Curve25519Kex::new(); - let server_kex = Curve25519Kex::new(); + let mut client_kex = Curve25519Kex::new(); + let mut server_kex = Curve25519Kex::new(); // 客户端计算共享密钥 let client_secret = client_kex.compute_shared_secret(server_kex.public_key()).unwrap(); diff --git a/markbase-core/src/ssh_server/sshbuf.rs b/markbase-core/src/ssh_server/sshbuf.rs index a4d6908..2015d36 100644 --- a/markbase-core/src/ssh_server/sshbuf.rs +++ b/markbase-core/src/ssh_server/sshbuf.rs @@ -279,14 +279,16 @@ mod tests { fn test_sshbuf_basic() { let mut buf = SshBuf::new(); - // Test reserve - let space = buf.reserve(10).unwrap(); - assert_eq!(space.len(), 10); - assert_eq!(buf.len(), 10); + // Test reserve - write into reserved space + { + let space = buf.reserve(10).unwrap(); + assert_eq!(space.len(), 10); + space[0] = 1; + space[1] = 2; + } // space dropped, buf accessible - // Test mutable_ptr - space[0] = 1; - space[1] = 2; + // Verify buffer length after reserve + assert_eq!(buf.len(), 10); let ptr = buf.mutable_ptr(); assert_eq!(ptr[0], 1); assert_eq!(ptr[1], 2);