限制视觉绑定处理图的解码规模

在解码前限制 base64 字节数并校验图像宽高,避免异常响应造成过量内存分配。
This commit is contained in:
2026-09-12 21:31:13 +08:00
parent d1a03aec0e
commit 584da5b76b
@@ -1,11 +1,13 @@
use super::area::MIN_VISIBLE_ALPHA;
use base64::Engine as _;
use image::{ImageFormat, Rgba, RgbaImage};
use image::{ImageFormat, ImageReader, Rgba, RgbaImage};
use std::fs;
use std::io::Cursor;
use std::path::{Path, PathBuf};
pub(crate) const VISUAL_BINDING_TRANSPARENT_MARKER_RGBA: [u8; 4] = [255, 0, 255, 255];
const MAX_PROCESSED_IMAGE_BYTES: usize = 64 * 1024 * 1024;
const MAX_PROCESSED_IMAGE_DIMENSION: u32 = 2880;
pub(crate) async fn preprocess_for_visual_binding(
processed_url: String,
@@ -29,6 +31,21 @@ fn preprocess_for_visual_binding_blocking(
let bytes = base64::engine::general_purpose::STANDARD
.decode(encoded.trim())
.map_err(|error| format!("解析处理图失败:{error}"))?;
if bytes.len() > MAX_PROCESSED_IMAGE_BYTES {
return Err(format!(
"处理图超过 {} MiB 字节上限",
MAX_PROCESSED_IMAGE_BYTES / 1024 / 1024
));
}
let dimensions = ImageReader::new(Cursor::new(&bytes))
.with_guessed_format()
.map_err(|error| format!("解析处理图格式失败:{error}"))?
.into_dimensions()
.map_err(|error| format!("读取处理图尺寸失败:{error}"))?;
if dimensions.0 > MAX_PROCESSED_IMAGE_DIMENSION || dimensions.1 > MAX_PROCESSED_IMAGE_DIMENSION
{
return Err("处理图尺寸超出上限".to_string());
}
let mut image = image::load_from_memory(&bytes)
.map_err(|error| format!("解码处理图失败:{error}"))?
.to_rgba8();