From 3ecd4efcbb907672e1f8382313f46120fc173adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Wed, 7 Oct 2026 10:51:01 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AF=BB=E5=8F=96=E5=8F=91=E5=B8=83=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E5=89=8D=E5=85=88=E6=8C=89=E4=BD=93=E7=A7=AF=E4=B8=8A?= =?UTF-8?q?=E9=99=90=E5=A4=B1=E8=B4=A5=E5=85=B3=E9=97=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - read_draft_image 先看 metadata.len(),超过 8MB(对齐服务端单图上限)直接返回错误 - 避免草稿指向超大本地文件时先把宿主内存读满,再由服务端事后拒绝 - 补稀疏大文件定向测试 --- .../src/game_distribution_publish.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/apps/ai-game-creator-shell/src-tauri/src/game_distribution_publish.rs b/apps/ai-game-creator-shell/src-tauri/src/game_distribution_publish.rs index f8e86833f..207efb87d 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/game_distribution_publish.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/game_distribution_publish.rs @@ -1062,9 +1062,18 @@ fn image_content_type(relative_path: &str) -> Result<&'static str, String> { } } +/// 单张发布图片的读取上限,与服务端 `MAX_SINGLE_MEDIA_BYTES` 保持一致:先看体积再读, +/// 避免草稿指向一个超大本地文件时先把宿主内存顶爆、再由服务端事后拒绝。 +const MAX_DRAFT_MEDIA_BYTES: u64 = 8 * 1024 * 1024; + /// 读一张草稿声明的项目内图片:路径先过宿主既有门禁(拒符号链接/越界),再读原始字节。 fn read_draft_image(root: &Path, relative_path: &str) -> Result { let absolute = crate::project::resolve_local_project_path(root, relative_path)?; + let metadata = std::fs::metadata(&absolute) + .map_err(|error| format!("读取发布图片「{relative_path}」失败:{error}"))?; + if metadata.len() > MAX_DRAFT_MEDIA_BYTES { + return Err(format!("发布图片「{relative_path}」超过 8MB 大小限制")); + } let bytes = std::fs::read(&absolute) .map_err(|error| format!("读取发布图片「{relative_path}」失败:{error}"))?; if bytes.is_empty() { @@ -1899,6 +1908,17 @@ mod tests { } } + #[test] + fn read_draft_image_rejects_oversized_files_before_reading() { + let root = fixture_root("oversized"); + let file = std::fs::File::create(root.join("huge.png")).unwrap(); + file.set_len(MAX_DRAFT_MEDIA_BYTES + 1).unwrap(); + drop(file); + + let error = read_draft_image(&root, "huge.png").expect_err("must reject oversized media"); + assert!(error.contains("超过 8MB"), "{error}"); + } + #[test] fn resolve_publish_media_reads_local_cover_and_screenshots_from_the_draft() { let root = fixture_root("local");