mirror of
https://github.com/TheFunny/TelegramTwitterMediaBot.git
synced 2026-09-24 23:42:18 +00:00
fix: bound ugoira archive expansion
This commit is contained in:
@@ -210,9 +210,17 @@ impl PixivAPI {
|
|||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
let metadata = self.ugoira_metadata(illust_id).await?;
|
let metadata = self.ugoira_metadata(illust_id).await?;
|
||||||
|
const MAX_UGOIRA_FRAMES: usize = 5_000;
|
||||||
|
const MAX_UGOIRA_UNPACKED_BYTES: u64 = 512 * 1024 * 1024;
|
||||||
if metadata.frames.is_empty() {
|
if metadata.frames.is_empty() {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
if metadata.frames.len() > MAX_UGOIRA_FRAMES {
|
||||||
|
return Err(PixivError::Api(format!(
|
||||||
|
"ugoira has too many frames: {}",
|
||||||
|
metadata.frames.len()
|
||||||
|
)));
|
||||||
|
}
|
||||||
let zip_url = metadata
|
let zip_url = metadata
|
||||||
.zip_url
|
.zip_url
|
||||||
.clone()
|
.clone()
|
||||||
@@ -267,10 +275,6 @@ impl PixivAPI {
|
|||||||
.prefix(crate::TEMP_FILE_PREFIX)
|
.prefix(crate::TEMP_FILE_PREFIX)
|
||||||
.tempdir()
|
.tempdir()
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
// Extract frames to canonical zero-padded names; pixiv ugoira
|
|
||||||
// frames are uniformly jpg or png per artwork. The zip is read
|
|
||||||
// from disk; `zip_file` stays alive for the whole extraction.
|
|
||||||
let mut archive = zip::ZipArchive::new(
|
let mut archive = zip::ZipArchive::new(
|
||||||
std::fs::File::open(zip_file.path()).map_err(|e| e.to_string())?,
|
std::fs::File::open(zip_file.path()).map_err(|e| e.to_string())?,
|
||||||
)
|
)
|
||||||
@@ -278,34 +282,15 @@ impl PixivAPI {
|
|||||||
if archive.is_empty() {
|
if archive.is_empty() {
|
||||||
return Err("empty frame zip".to_string());
|
return Err("empty frame zip".to_string());
|
||||||
}
|
}
|
||||||
// Uniform jpg or png per artwork; sniff the first entry's
|
if archive.len() > MAX_UGOIRA_FRAMES {
|
||||||
// magic bytes instead of trusting its filename.
|
return Err("ugoira frame zip has too many entries".to_string());
|
||||||
let first = archive.by_index(0).map_err(|e| e.to_string())?;
|
|
||||||
let mut first_bytes = Vec::new();
|
|
||||||
first
|
|
||||||
.take(64 * 1024 * 1024 + 1)
|
|
||||||
.read_to_end(&mut first_bytes)
|
|
||||||
.map_err(|e| e.to_string())?;
|
|
||||||
if first_bytes.len() > 64 * 1024 * 1024 {
|
|
||||||
return Err("frame exceeds size cap".to_string());
|
|
||||||
}
|
}
|
||||||
let extension = if first_bytes.starts_with(&[0xFF, 0xD8]) {
|
|
||||||
"jpg"
|
|
||||||
} else if first_bytes.starts_with(b"\x89PNG") {
|
|
||||||
"png"
|
|
||||||
} else {
|
|
||||||
"jpg"
|
|
||||||
};
|
|
||||||
let mut count = 0usize;
|
let mut count = 0usize;
|
||||||
{
|
let mut unpacked = 0u64;
|
||||||
let path = frames_dir
|
let mut extension = "jpg";
|
||||||
.path()
|
for i in 0..archive.len() {
|
||||||
.join(format!("img_{count:05}.{extension}"));
|
let mut entry = archive.by_index(i).map_err(|e| e.to_string())?;
|
||||||
std::fs::write(&path, &first_bytes).map_err(|e| e.to_string())?;
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
for i in 1..archive.len() {
|
|
||||||
let entry = archive.by_index(i).map_err(|e| e.to_string())?;
|
|
||||||
if entry.size() > 64 * 1024 * 1024 {
|
if entry.size() > 64 * 1024 * 1024 {
|
||||||
return Err(format!("frame {i} exceeds size cap"));
|
return Err(format!("frame {i} exceeds size cap"));
|
||||||
}
|
}
|
||||||
@@ -317,6 +302,21 @@ impl PixivAPI {
|
|||||||
if bytes.len() > 64 * 1024 * 1024 {
|
if bytes.len() > 64 * 1024 * 1024 {
|
||||||
return Err(format!("frame {i} exceeds size cap"));
|
return Err(format!("frame {i} exceeds size cap"));
|
||||||
}
|
}
|
||||||
|
unpacked = unpacked
|
||||||
|
.checked_add(bytes.len() as u64)
|
||||||
|
.ok_or_else(|| "ugoira unpacked size overflow".to_string())?;
|
||||||
|
if unpacked > MAX_UGOIRA_UNPACKED_BYTES {
|
||||||
|
return Err("ugoira exceeds total unpacked size cap".to_string());
|
||||||
|
}
|
||||||
|
if i == 0 {
|
||||||
|
extension = if bytes.starts_with(&[0xFF, 0xD8]) {
|
||||||
|
"jpg"
|
||||||
|
} else if bytes.starts_with(b"\x89PNG") {
|
||||||
|
"png"
|
||||||
|
} else {
|
||||||
|
"jpg"
|
||||||
|
};
|
||||||
|
}
|
||||||
let path = frames_dir
|
let path = frames_dir
|
||||||
.path()
|
.path()
|
||||||
.join(format!("img_{count:05}.{extension}"));
|
.join(format!("img_{count:05}.{extension}"));
|
||||||
@@ -326,7 +326,6 @@ impl PixivAPI {
|
|||||||
if count == 0 {
|
if count == 0 {
|
||||||
return Err("empty frame zip".to_string());
|
return Err("empty frame zip".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constant rate from the median frame delay (ms).
|
// Constant rate from the median frame delay (ms).
|
||||||
let mut delays = frame_delays;
|
let mut delays = frame_delays;
|
||||||
delays.sort_unstable();
|
delays.sort_unstable();
|
||||||
|
|||||||
Reference in New Issue
Block a user