Skip to content

Commit 59cbdf4

Browse files
committed
Merge branch 'main' into errors-patch
2 parents 2ad903c + cccf6c7 commit 59cbdf4

File tree

1 file changed

+36
-14
lines changed

1 file changed

+36
-14
lines changed

src/mod_zip.rs

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,16 @@ pub enum ModZipError {
3232
InvalidModJson(String),
3333
#[error("Invalid binaries: {0}")]
3434
InvalidBinaries(String),
35-
#[error("{0}")]
36-
GenericError(String),
3735
}
3836

3937
pub fn extract_mod_logo(file: &mut ZipFile<Cursor<Bytes>>) -> Result<Vec<u8>, ModZipError> {
38+
const FIVE_MEGABYTES: u64 = 5 * 1000 * 1000;
39+
if file.size() > FIVE_MEGABYTES {
40+
return Err(ModZipError::InvalidLogo(
41+
"Logo size excedes max allowed size (5 MB)".into(),
42+
));
43+
}
44+
4045
let mut logo: Vec<u8> = Vec::with_capacity(file.size() as usize);
4146
file.read_to_end(&mut logo)
4247
.inspect_err(|e| log::error!("logo.png read fail: {}", e))?;
@@ -83,6 +88,13 @@ pub fn extract_mod_logo(file: &mut ZipFile<Cursor<Bytes>>) -> Result<Vec<u8>, Mo
8388
}
8489

8590
pub fn validate_mod_logo(file: &mut ZipFile<Cursor<Bytes>>) -> Result<(), ModZipError> {
91+
const FIVE_MEGABYTES: u64 = 5 * 1000 * 1000;
92+
if file.size() > FIVE_MEGABYTES {
93+
return Err(ModZipError::InvalidLogo(
94+
"Logo size excedes max allowed size (5 MB)".into(),
95+
));
96+
}
97+
8698
let mut logo: Vec<u8> = Vec::with_capacity(file.size() as usize);
8799
file.read_to_end(&mut logo)
88100
.inspect_err(|e| log::error!("logo.png read fail: {}", e))?;
@@ -133,23 +145,33 @@ pub fn bytes_to_ziparchive(bytes: Bytes) -> Result<ZipArchive<Cursor<Bytes>>, Mo
133145
}
134146

135147
async fn download(url: &str, limit_mb: u32) -> Result<Bytes, ModZipError> {
136-
let limit_bytes = limit_mb * 1_000_000;
137-
let response = reqwest::get(url)
148+
let limit_bytes: u64 = limit_mb as u64 * 1_000_000;
149+
let mut response = reqwest::get(url)
138150
.await
139151
.inspect_err(|e| log::error!("Failed to fetch .geode file: {e}"))?;
140152

141-
let len = response.content_length().ok_or(ModZipError::GenericError(
142-
"Couldn't determine .geode file size".into(),
143-
))?;
153+
// Check Content-Length, but the server can lie about this, so we'll also stream the file
154+
// If the header is somehow unavailable, we'll just check the size when streaming
155+
let content_length = response.content_length().unwrap_or(0);
144156

145-
if len > limit_bytes as u64 {
146-
let len_mb = len / 1_000_000;
157+
if content_length > limit_bytes {
158+
let len_mb = content_length / 1_000_000;
147159
return Err(ModZipError::ModFileTooLarge(len_mb, limit_mb.into()));
148160
}
149161

150-
response
151-
.bytes()
152-
.await
153-
.inspect_err(|e| log::error!("Failed to get bytes from .geode: {}", e))
154-
.map_err(|e| e.into())
162+
let mut data: Vec<u8> = Vec::with_capacity(content_length as usize);
163+
164+
let mut streamed: u64 = 0;
165+
while let Some(chunk) = response.chunk().await? {
166+
streamed += chunk.len() as u64;
167+
168+
if streamed > limit_bytes {
169+
let len_mb = streamed / 1_000_000;
170+
return Err(ModZipError::ModFileTooLarge(len_mb, limit_mb.into()));
171+
}
172+
173+
data.extend_from_slice(&chunk);
174+
}
175+
176+
Ok(Bytes::from(data))
155177
}

0 commit comments

Comments
 (0)