This commit is contained in:
fengchuanhn@gmail.com
2026-05-18 10:18:49 +08:00
parent beb5eaeb42
commit 6cc305f5e8
5 changed files with 253 additions and 5 deletions

View File

@@ -0,0 +1,46 @@
//! 本地文件读取(供前端播放 Node 生成的临时音频等)
use base64::{engine::general_purpose::STANDARD, Engine as _};
use std::path::{Component, Path, PathBuf};
fn normalize_path(path: &str) -> PathBuf {
Path::new(path)
.components()
.filter(|c| !matches!(c, Component::ParentDir))
.collect()
}
/// 仅允许读取临时目录下的试听/流水线产物,避免任意路径读取。
fn is_allowed_local_media(path: &Path) -> bool {
let lower = path.to_string_lossy().to_lowercase();
if lower.contains("aiclient-voice-preview-cache")
|| lower.contains("aiclient-node-pipeline")
{
return true;
}
if let Ok(temp) = std::env::temp_dir().canonicalize() {
if let Ok(canonical) = path.canonicalize() {
return canonical.starts_with(&temp);
}
}
false
}
/// 读取本地文件为 base64用于 `<audio src="data:audio/wav;base64,...">`
#[tauri::command]
pub async fn read_local_file_base64(path: String) -> Result<String, String> {
let normalized = normalize_path(path.trim());
if normalized.as_os_str().is_empty() {
return Err("路径为空".into());
}
if !normalized.is_file() {
return Err(format!("文件不存在: {}", normalized.display()));
}
if !is_allowed_local_media(&normalized) {
return Err("不允许读取该路径下的文件".into());
}
let bytes = tokio::fs::read(&normalized)
.await
.map_err(|e| format!("读取文件失败: {e}"))?;
Ok(STANDARD.encode(bytes))
}

View File

@@ -1,5 +1,6 @@
pub mod api;
pub mod app_config;
pub mod auth;
pub mod fs_util;
pub mod nodejs;
pub mod quickjs;

View File

@@ -60,6 +60,7 @@ pub fn run() {
commands::nodejs::run_nodejs_script,
commands::nodejs::run_nodejs_script_source,
commands::nodejs::list_nodejs_scripts,
commands::fs_util::read_local_file_base64,
])
.run(tauri::generate_context!())
.expect("error while running tauri application");