1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use std::fs::File;
use std::io::Read;
use std::path::Path;
use crate::types::{Limits, OpenPackError};
impl Limits {
/// Provides very restrictive limits for highly untrusted archives.
///
/// # Examples
///
/// ```
/// use openpack::Limits;
/// let limits = Limits::strict();
/// ```
pub fn strict() -> Self {
Self {
max_archive_size: 10 * 1024 * 1024,
max_entry_uncompressed_size: 2 * 1024 * 1024,
max_total_uncompressed_size: 20 * 1024 * 1024,
max_entries: 100,
max_compression_ratio: 20.0,
}
}
/// Provides extremely loose limits for trusted archives only.
///
/// # Examples
///
/// ```
/// use openpack::Limits;
/// let limits = Limits::permissive();
/// ```
pub fn permissive() -> Self {
Self {
max_archive_size: 2 * 1024 * 1024 * 1024,
max_entry_uncompressed_size: 1024 * 1024 * 1024,
max_total_uncompressed_size: 4 * 1024 * 1024 * 1024,
max_entries: 100000,
max_compression_ratio: 1000.0,
}
}
/// Parses limits from a TOML string.
///
/// # Examples
///
/// ```
/// use openpack::Limits;
/// let toml_str = r#"
/// max_archive_size = 104857600
/// max_entry_uncompressed_size = 10485760
/// max_total_uncompressed_size = 52428800
/// max_entries = 1000
/// max_compression_ratio = 50.0
/// "#;
/// let limits = Limits::from_toml(toml_str).unwrap();
/// ```
pub fn from_toml(raw: &str) -> Result<Self, OpenPackError> {
let limits: Self = toml::from_str(raw)
.map_err(|err| OpenPackError::InvalidConfig(err.to_string()))?;
limits.validate()?;
Ok(limits)
}
pub(crate) fn validate(&self) -> Result<(), OpenPackError> {
if self.max_archive_size == 0 {
return Err(OpenPackError::InvalidConfig(
"max_archive_size must be greater than 0".into(),
));
}
if self.max_entry_uncompressed_size == 0 {
return Err(OpenPackError::InvalidConfig(
"max_entry_uncompressed_size must be greater than 0".into(),
));
}
if self.max_total_uncompressed_size == 0 {
return Err(OpenPackError::InvalidConfig(
"max_total_uncompressed_size must be greater than 0".into(),
));
}
if self.max_entries == 0 {
return Err(OpenPackError::InvalidConfig(
"max_entries must be greater than 0".into(),
));
}
if self.max_total_uncompressed_size < self.max_entry_uncompressed_size {
return Err(OpenPackError::InvalidConfig(
"max_total_uncompressed_size must be >= max_entry_uncompressed_size".into(),
));
}
if self.max_compression_ratio.is_nan()
|| self.max_compression_ratio.is_infinite()
|| self.max_compression_ratio <= 0.0
{
return Err(OpenPackError::InvalidConfig(
"max_compression_ratio must be a positive finite number".into(),
));
}
Ok(())
}
/// Parses limits from a TOML file.
pub fn from_toml_file(path: &Path) -> Result<Self, OpenPackError> {
let mut file = File::open(path)?;
let mut raw = String::new();
file.read_to_string(&mut raw)?;
Self::from_toml(&raw)
}
/// Loads the builtin limits compiled into the binary.
///
/// # Examples
///
/// ```
/// use openpack::Limits;
/// let limits = Limits::builtin();
/// ```
pub fn builtin() -> Self {
// The bundled config is trusted, but we still validate in case it is
// accidentally corrupted during editing.
Self::from_toml(include_str!("../config/limits.toml")).unwrap_or_else(|_| Self::default())
}
}