Skip to main content

multi_cbor/
config.rs

1//! Configuration for CBOR deserialization limits and security settings.
2
3/// Configuration for CBOR deserializer to prevent `DoS` attacks.
4///
5/// This struct provides configurable limits for deserialization to protect against
6/// malicious inputs that could consume excessive memory or CPU resources.
7///
8/// # Examples
9///
10/// ```
11/// use multi_cbor::config::DeserializerConfig;
12///
13/// let config = DeserializerConfig::default()
14///     .max_array_size(1000)
15///     .max_map_size(500)
16///     .max_recursion_depth(64);
17/// ```
18#[derive(Debug, Clone, Copy)]
19pub struct DeserializerConfig {
20    /// Maximum number of elements allowed in an array
21    max_array_size: Option<usize>,
22    /// Maximum number of key-value pairs allowed in a map
23    max_map_size: Option<usize>,
24    /// Maximum recursion depth for nested structures
25    max_recursion_depth: u8,
26    /// Maximum number of iterations for indefinite-length structures
27    max_indefinite_iterations: Option<usize>,
28}
29
30impl Default for DeserializerConfig {
31    /// Creates a default configuration with reasonable limits.
32    ///
33    /// Default limits:
34    /// - Max array size: 100,000 elements
35    /// - Max map size: 100,000 key-value pairs
36    /// - Max recursion depth: 128 levels
37    /// - Max indefinite iterations: 100,000
38    fn default() -> Self {
39        Self {
40            max_array_size: Some(100_000),
41            max_map_size: Some(100_000),
42            max_recursion_depth: 128,
43            max_indefinite_iterations: Some(100_000),
44        }
45    }
46}
47
48impl DeserializerConfig {
49    /// Creates a new configuration with no limits (use with caution).
50    ///
51    /// This is potentially dangerous as it allows unbounded resource consumption.
52    /// Only use this when you have full control over the input data.
53    #[must_use]
54    pub const fn unlimited() -> Self {
55        Self {
56            max_array_size: None,
57            max_map_size: None,
58            max_recursion_depth: 255,
59            max_indefinite_iterations: None,
60        }
61    }
62
63    /// Creates a strict configuration with conservative limits for untrusted input.
64    ///
65    /// Strict limits:
66    /// - Max array size: 1,000 elements
67    /// - Max map size: 1,000 key-value pairs
68    /// - Max recursion depth: 32 levels
69    /// - Max indefinite iterations: 1,000
70    #[must_use]
71    pub const fn strict() -> Self {
72        Self {
73            max_array_size: Some(1_000),
74            max_map_size: Some(1_000),
75            max_recursion_depth: 32,
76            max_indefinite_iterations: Some(1_000),
77        }
78    }
79
80    /// Sets the maximum number of elements allowed in an array.
81    ///
82    /// Pass `None` to disable this limit (not recommended for untrusted input).
83    #[must_use]
84    pub const fn max_array_size(mut self, limit: usize) -> Self {
85        self.max_array_size = Some(limit);
86        self
87    }
88
89    /// Removes the limit on array size (use with caution).
90    #[must_use]
91    pub const fn unlimited_array_size(mut self) -> Self {
92        self.max_array_size = None;
93        self
94    }
95
96    /// Sets the maximum number of key-value pairs allowed in a map.
97    ///
98    /// Pass `None` to disable this limit (not recommended for untrusted input).
99    #[must_use]
100    pub const fn max_map_size(mut self, limit: usize) -> Self {
101        self.max_map_size = Some(limit);
102        self
103    }
104
105    /// Removes the limit on map size (use with caution).
106    #[must_use]
107    pub const fn unlimited_map_size(mut self) -> Self {
108        self.max_map_size = None;
109        self
110    }
111
112    /// Sets the maximum recursion depth for nested structures.
113    ///
114    /// Lower values provide better `DoS` protection but may reject legitimate deeply nested data.
115    #[must_use]
116    pub const fn max_recursion_depth(mut self, depth: u8) -> Self {
117        self.max_recursion_depth = depth;
118        self
119    }
120
121    /// Sets the maximum number of iterations for indefinite-length structures.
122    ///
123    /// This prevents attackers from sending indefinite-length arrays or maps with
124    /// extremely large numbers of elements.
125    #[must_use]
126    pub const fn max_indefinite_iterations(mut self, limit: usize) -> Self {
127        self.max_indefinite_iterations = Some(limit);
128        self
129    }
130
131    /// Removes the limit on indefinite-length iterations (use with caution).
132    #[must_use]
133    pub const fn unlimited_indefinite_iterations(mut self) -> Self {
134        self.max_indefinite_iterations = None;
135        self
136    }
137
138    /// Returns the maximum array size limit.
139    #[must_use]
140    pub const fn get_max_array_size(&self) -> Option<usize> {
141        self.max_array_size
142    }
143
144    /// Returns the maximum map size limit.
145    #[must_use]
146    pub const fn get_max_map_size(&self) -> Option<usize> {
147        self.max_map_size
148    }
149
150    /// Returns the maximum recursion depth.
151    #[must_use]
152    pub const fn get_max_recursion_depth(&self) -> u8 {
153        self.max_recursion_depth
154    }
155
156    /// Returns the maximum indefinite iterations limit.
157    #[must_use]
158    pub const fn get_max_indefinite_iterations(&self) -> Option<usize> {
159        self.max_indefinite_iterations
160    }
161}
162
163#[cfg(test)]
164mod tests {
165    use super::*;
166
167    #[test]
168    fn test_default_config() {
169        let config = DeserializerConfig::default();
170        assert_eq!(config.get_max_array_size(), Some(100_000));
171        assert_eq!(config.get_max_map_size(), Some(100_000));
172        assert_eq!(config.get_max_recursion_depth(), 128);
173        assert_eq!(config.get_max_indefinite_iterations(), Some(100_000));
174    }
175
176    #[test]
177    fn test_unlimited_config() {
178        let config = DeserializerConfig::unlimited();
179        assert_eq!(config.get_max_array_size(), None);
180        assert_eq!(config.get_max_map_size(), None);
181        assert_eq!(config.get_max_recursion_depth(), 255);
182        assert_eq!(config.get_max_indefinite_iterations(), None);
183    }
184
185    #[test]
186    fn test_strict_config() {
187        let config = DeserializerConfig::strict();
188        assert_eq!(config.get_max_array_size(), Some(1_000));
189        assert_eq!(config.get_max_map_size(), Some(1_000));
190        assert_eq!(config.get_max_recursion_depth(), 32);
191        assert_eq!(config.get_max_indefinite_iterations(), Some(1_000));
192    }
193
194    #[test]
195    fn test_custom_config() {
196        let config = DeserializerConfig::default()
197            .max_array_size(500)
198            .max_map_size(250)
199            .max_recursion_depth(16)
200            .max_indefinite_iterations(1000);
201
202        assert_eq!(config.get_max_array_size(), Some(500));
203        assert_eq!(config.get_max_map_size(), Some(250));
204        assert_eq!(config.get_max_recursion_depth(), 16);
205        assert_eq!(config.get_max_indefinite_iterations(), Some(1000));
206    }
207
208    #[test]
209    fn test_unlimited_modifications() {
210        let config = DeserializerConfig::default()
211            .unlimited_array_size()
212            .unlimited_map_size()
213            .unlimited_indefinite_iterations();
214
215        assert_eq!(config.get_max_array_size(), None);
216        assert_eq!(config.get_max_map_size(), None);
217        assert_eq!(config.get_max_indefinite_iterations(), None);
218    }
219}