diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/persistence.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/persistence.rs index 80fd9f0a2..32b49adc6 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/persistence.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/persistence.rs @@ -2,6 +2,8 @@ use super::model::*; use crate::ui_editor::commands::separation::*; use std::fs; use std::path::{Path, PathBuf}; + +const SEPARATION_STATE_MAX_BYTES: usize = 8 * 1024 * 1024; pub fn separation_sidecar_dir(root: &Path, asset_id: &str) -> Result { if asset_id.trim().is_empty() || asset_id.trim() != asset_id { app_log!("ui_separation.error stage=sidecar_dir reason=invalid_asset_id"); @@ -97,10 +99,31 @@ pub fn read_separation_state(path: &Path) -> Result { .and_then(|name| name.to_str()) .unwrap_or("") ); + let metadata = fs::metadata(path).map_err(|error| { + app_log!("ui_separation.error stage=state_read reason=metadata error={error}"); + format!("读取 separation state 信息失败:{error}") + })?; + if metadata.len() > SEPARATION_STATE_MAX_BYTES as u64 { + app_log!( + "ui_separation.error stage=state_read reason=too_large bytes={} max_bytes={}", + metadata.len(), + SEPARATION_STATE_MAX_BYTES + ); + return Err(format!( + "separation state 超过 {} 字节上限", + SEPARATION_STATE_MAX_BYTES + )); + } let bytes = fs::read(path).map_err(|error| { app_log!("ui_separation.error stage=state_read reason=read error={error}"); format!("读取 separation state 失败:{error}") })?; + if bytes.len() > SEPARATION_STATE_MAX_BYTES { + return Err(format!( + "separation state 超过 {} 字节上限", + SEPARATION_STATE_MAX_BYTES + )); + } let state: SeparationState = serde_json::from_slice(&bytes).map_err(|error| { app_log!("ui_separation.error stage=state_read reason=parse error={error}"); format!("解析 separation state 失败:{error}")