Skip to main content

scrubkit_core/
lib.rs

1// crates/scrubkit-core/src/lib.rs
2
3pub mod jpeg;
4pub mod png;
5use jpeg::JpegScrubber;
6use png::PngScrubber;
7use thiserror::Error;
8
9/// A universal error type for all scrubbing operations.
10#[derive(Error, Debug)]
11pub enum ScrubError {
12    #[error("Unsupported file type: {0}")]
13    UnsupportedFileType(String),
14
15    #[error("File parsing failed: {0}")]
16    ParsingError(String),
17
18    #[error("I/O error: {0}")]
19    IoError(#[from] std::io::Error),
20
21    #[error("An unknown error occurred")]
22    Unknown,
23}
24
25/// Represents a single piece of metadata.
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct MetadataEntry {
28    pub key: String,
29    pub value: String,
30    pub category: String, // e.g., "EXIF", "GPS", "Document Properties"
31}
32
33/// The result of a successful scrub operation.
34#[derive(Debug)]
35pub struct ScrubResult {
36    /// The bytes of the new, cleaned file.
37    pub cleaned_file_bytes: Vec<u8>,
38    /// A report of the metadata entries that were removed.
39    pub metadata_removed: Vec<MetadataEntry>,
40}
41
42/// The central trait of our library.
43/// Any file type we want to support must implement this trait.
44pub trait Scrubber {
45    /// Creates a new Scrubber instance from file bytes.
46    /// This will also parse the file to ensure it's valid.
47    fn new(file_bytes: Vec<u8>) -> Result<Self, ScrubError>
48    where
49        Self: Sized;
50
51    /// Returns all found metadata in a structured format.
52    fn view_metadata(&self) -> Result<Vec<MetadataEntry>, ScrubError>;
53
54    /// Removes all identifiable metadata.
55    fn scrub(&self) -> Result<ScrubResult, ScrubError>;
56}
57
58/// Detects the file type and returns the appropriate scrubber.
59/// This is the main entry point for consumers of the library.
60pub fn scrubber_for_file(file_bytes: Vec<u8>) -> Result<Box<dyn Scrubber>, ScrubError> {
61    // PNG files start with a specific 8-byte signature.
62    if file_bytes.len() > 8 && file_bytes[0..8] == [137, 80, 78, 71, 13, 10, 26, 10] {
63        let scrubber = PngScrubber::new(file_bytes)?;
64        return Ok(Box::new(scrubber));
65    }
66
67    // JPEG files start with 0xFFD8.
68    if file_bytes.len() > 2 && file_bytes[0..2] == [0xFF, 0xD8] {
69        let scrubber = JpegScrubber::new(file_bytes)?;
70        return Ok(Box::new(scrubber));
71    }
72
73    Err(ScrubError::UnsupportedFileType(
74        "Could not determine file type.".to_string(),
75    ))
76}