leptos_sync_core/reliability/data_integrity/
checksum.rs

1//! Checksum verification for data corruption detection
2
3use super::super::IntegrityError;
4use serde::{Deserialize, Serialize};
5use sha2::{Digest, Sha256};
6use std::collections::HashMap;
7
8/// Checksum algorithm types
9#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
10pub enum ChecksumAlgorithm {
11    /// SHA-256 checksum
12    Sha256,
13    /// MD5 checksum (less secure, faster)
14    Md5,
15    /// CRC32 checksum (fastest, least secure)
16    Crc32,
17}
18
19/// Configuration for checksum verification
20#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
21pub struct ChecksumConfig {
22    /// Default checksum algorithm
23    pub algorithm: ChecksumAlgorithm,
24    /// Whether to verify checksums on read
25    pub verify_on_read: bool,
26    /// Whether to compute checksums on write
27    pub compute_on_write: bool,
28}
29
30impl Default for ChecksumConfig {
31    fn default() -> Self {
32        Self {
33            algorithm: ChecksumAlgorithm::Sha256,
34            verify_on_read: true,
35            compute_on_write: true,
36        }
37    }
38}
39
40/// Checksum verifier for data integrity
41#[derive(Debug, Clone)]
42pub struct ChecksumVerifier {
43    /// Configuration
44    config: ChecksumConfig,
45    /// Cache of computed checksums
46    checksum_cache: HashMap<String, String>,
47}
48
49impl ChecksumVerifier {
50    /// Create a new checksum verifier
51    pub fn new() -> Self {
52        Self {
53            config: ChecksumConfig::default(),
54            checksum_cache: HashMap::new(),
55        }
56    }
57
58    /// Create a new checksum verifier with configuration
59    pub fn with_config(config: ChecksumConfig) -> Self {
60        Self {
61            config,
62            checksum_cache: HashMap::new(),
63        }
64    }
65
66    /// Compute checksum for data
67    pub fn compute_checksum(&mut self, data: &[u8], key: &str) -> Result<String, IntegrityError> {
68        let checksum = match self.config.algorithm {
69            ChecksumAlgorithm::Sha256 => {
70                let mut hasher = Sha256::new();
71                hasher.update(data);
72                format!("{:x}", hasher.finalize())
73            }
74            ChecksumAlgorithm::Md5 => {
75                // Note: MD5 implementation would go here
76                "md5_placeholder".to_string()
77            }
78            ChecksumAlgorithm::Crc32 => {
79                // Note: CRC32 implementation would go here
80                "crc32_placeholder".to_string()
81            }
82        };
83
84        // Cache the checksum
85        self.checksum_cache
86            .insert(key.to_string(), checksum.clone());
87
88        Ok(checksum)
89    }
90
91    /// Verify checksum for data
92    pub fn verify_checksum(
93        &self,
94        data: &[u8],
95        expected_checksum: &str,
96    ) -> Result<bool, IntegrityError> {
97        let computed_checksum = match self.config.algorithm {
98            ChecksumAlgorithm::Sha256 => {
99                let mut hasher = Sha256::new();
100                hasher.update(data);
101                format!("{:x}", hasher.finalize())
102            }
103            ChecksumAlgorithm::Md5 => "md5_placeholder".to_string(),
104            ChecksumAlgorithm::Crc32 => "crc32_placeholder".to_string(),
105        };
106
107        Ok(computed_checksum == expected_checksum)
108    }
109
110    /// Get cached checksum
111    pub fn get_cached_checksum(&self, key: &str) -> Option<&String> {
112        self.checksum_cache.get(key)
113    }
114
115    /// Clear checksum cache
116    pub fn clear_cache(&mut self) {
117        self.checksum_cache.clear();
118    }
119
120    /// Get configuration
121    pub fn config(&self) -> &ChecksumConfig {
122        &self.config
123    }
124}
125
126impl Default for ChecksumVerifier {
127    fn default() -> Self {
128        Self::new()
129    }
130}
131
132#[cfg(test)]
133mod tests {
134    use super::*;
135
136    #[test]
137    fn test_checksum_verifier_creation() {
138        let verifier = ChecksumVerifier::new();
139        assert_eq!(verifier.config().algorithm, ChecksumAlgorithm::Sha256);
140        assert!(verifier.config().verify_on_read);
141        assert!(verifier.config().compute_on_write);
142    }
143
144    #[test]
145    fn test_checksum_verifier_with_config() {
146        let config = ChecksumConfig {
147            algorithm: ChecksumAlgorithm::Md5,
148            verify_on_read: false,
149            compute_on_write: true,
150        };
151        let verifier = ChecksumVerifier::with_config(config.clone());
152        assert_eq!(verifier.config().algorithm, ChecksumAlgorithm::Md5);
153        assert!(!verifier.config().verify_on_read);
154        assert!(verifier.config().compute_on_write);
155    }
156
157    #[test]
158    fn test_compute_checksum() {
159        let mut verifier = ChecksumVerifier::new();
160        let data = b"test data";
161        let key = "test_key";
162
163        let checksum = verifier.compute_checksum(data, key).unwrap();
164        assert!(!checksum.is_empty());
165
166        // Check if cached
167        assert!(verifier.get_cached_checksum(key).is_some());
168    }
169
170    #[test]
171    fn test_verify_checksum() {
172        let mut verifier = ChecksumVerifier::new();
173        let data = b"test data";
174        let key = "test_key";
175
176        let checksum = verifier.compute_checksum(data, key).unwrap();
177        let is_valid = verifier.verify_checksum(data, &checksum).unwrap();
178        assert!(is_valid);
179
180        // Test with wrong checksum
181        let is_invalid = verifier.verify_checksum(data, "wrong_checksum").unwrap();
182        assert!(!is_invalid);
183    }
184
185    #[test]
186    fn test_clear_cache() {
187        let mut verifier = ChecksumVerifier::new();
188        let data = b"test data";
189        let key = "test_key";
190
191        verifier.compute_checksum(data, key).unwrap();
192        assert!(verifier.get_cached_checksum(key).is_some());
193
194        verifier.clear_cache();
195        assert!(verifier.get_cached_checksum(key).is_none());
196    }
197}