From e35b0f0bbb71cda77c451301b3ffc37494b4a8f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=B1=BC=E5=BC=80=E5=8F=91?= Date: Tue, 26 May 2026 10:24:37 +0800 Subject: [PATCH] =?UTF-8?q?fix(rust):=20Windows=20=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=E5=A4=B1=E8=B4=A5=EF=BC=88canonicalize=20UNC?= =?UTF-8?q?=20=E5=89=8D=E7=BC=80=E4=B8=8D=E5=8C=B9=E9=85=8D=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在 Windows 上 std::fs::canonicalize() 会返回 \?\ 前缀的 UNC 路径 (如 \?\C:\Users\...),但 get_app_data_dir() 返回普通路径格式 (C:\Users\...)。PathBuf::starts_with() 做组件级比较时两者前缀 类型不同导致返回 false,所有本地文件操作都被错误拒绝。 修复:对允许目录也做 canonicalize(),使两边格式一致后再比较。 影响文件: - ffmpeg_cmd.rs: validate_safe_path() - commands/product.rs: delete_local_product, rename_local_product, export_product --- tauri-app/src-tauri/src/commands/product.rs | 9 ++++++--- tauri-app/src-tauri/src/ffmpeg_cmd.rs | 7 ++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/tauri-app/src-tauri/src/commands/product.rs b/tauri-app/src-tauri/src/commands/product.rs index d753681..18ebfa8 100644 --- a/tauri-app/src-tauri/src/commands/product.rs +++ b/tauri-app/src-tauri/src/commands/product.rs @@ -219,8 +219,9 @@ pub async fn delete_local_product(path: String) -> ApiResponse<()> { data: None, }, }; + let app_data_canonical = app_data.canonicalize().unwrap_or_else(|_| app_data.clone()); - if !canonical.starts_with(app_data) { + if !canonical.starts_with(&app_data_canonical) { return ApiResponse { code: 400, message: "路径不在允许范围内".to_string(), @@ -279,8 +280,9 @@ pub async fn rename_local_product(path: String, new_filename: String) -> ApiResp data: None, }, }; + let app_data_canonical = app_data.canonicalize().unwrap_or_else(|_| app_data.clone()); - if !canonical.starts_with(app_data) { + if !canonical.starts_with(&app_data_canonical) { return ApiResponse { code: 400, message: "路径不在允许范围内".to_string(), @@ -359,8 +361,9 @@ pub async fn export_product(source_path: String, target_path: String) -> ApiResp data: None, }, }; + let app_data_canonical = app_data.canonicalize().unwrap_or_else(|_| app_data.clone()); - if !source_canonical.starts_with(app_data) { + if !source_canonical.starts_with(&app_data_canonical) { return ApiResponse { code: 400, message: "源文件不在允许范围内".to_string(), diff --git a/tauri-app/src-tauri/src/ffmpeg_cmd.rs b/tauri-app/src-tauri/src/ffmpeg_cmd.rs index c2bfc82..42ac191 100644 --- a/tauri-app/src-tauri/src/ffmpeg_cmd.rs +++ b/tauri-app/src-tauri/src/ffmpeg_cmd.rs @@ -51,8 +51,13 @@ fn validate_safe_path(path: &str) -> Result { let canonical = abs_path.canonicalize() .unwrap_or(abs_path.clone()); + // 同时规范化允许目录(Windows 上 canonicalize 会添加 \\?\ 前缀, + // 必须与输入路径保持一致的规范化格式才能正确比较) + let allowed_canonical = allowed_dir.canonicalize() + .unwrap_or(allowed_dir.clone()); + // 检查是否在允许目录下 - if !canonical.starts_with(allowed_dir) { + if !canonical.starts_with(&allowed_canonical) { return Err(format!("路径不在允许目录内: {}", path.display())); }