fix(vnt-web): save_config 强制 .toml 后缀
问题:list_configs 只列出 *.toml 文件(service_http.rs:812),而 save_config 对文件名不做后缀校验,可保存出列表中不可见、无法通过 Web 界面再次选择的配置文件。 修复:新增 normalize_config_file_name——无扩展名时自动补 .toml,已是 .toml 保持不变,其他扩展名直接拒绝并返回错误提示。 测试:新增 test_normalize_config_file_name 覆盖补后缀/保持不变/拒绝 .txt/.json 三种情况,cargo test -p vnt-web 4 个测试全部通过。
This commit is contained in:
@@ -671,6 +671,16 @@ fn is_valid_file_name(file_name: &str) -> bool {
|
|||||||
&& !file_name.contains('\\')
|
&& !file_name.contains('\\')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 规范化配置文件名:无扩展名时补 .toml;扩展名不是 .toml 则拒绝。
|
||||||
|
/// list_configs 只列出 *.toml,不强制后缀会保存出列表中不可见的文件
|
||||||
|
fn normalize_config_file_name(file_name: String) -> Result<String, &'static str> {
|
||||||
|
match Path::new(&file_name).extension() {
|
||||||
|
None => Ok(format!("{file_name}.toml")),
|
||||||
|
Some(ext) if ext == "toml" => Ok(file_name),
|
||||||
|
Some(_) => Err("Config file name must end with .toml"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn start_vnt_handler(
|
async fn start_vnt_handler(
|
||||||
State(state): State<HttpAppState>,
|
State(state): State<HttpAppState>,
|
||||||
Json(req): Json<FileReq>,
|
Json(req): Json<FileReq>,
|
||||||
@@ -864,6 +874,11 @@ async fn save_config(Json(req): Json<SaveConfigReq>) -> Json<ApiResponse<()>> {
|
|||||||
return Json(ApiResponse::error("Invalid file name"));
|
return Json(ApiResponse::error("Invalid file name"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let file_name = match normalize_config_file_name(file_name) {
|
||||||
|
Ok(name) => name,
|
||||||
|
Err(msg) => return Json(ApiResponse::error(msg)),
|
||||||
|
};
|
||||||
|
|
||||||
let target_path = Path::new(CONFIG_DIR).join(&file_name);
|
let target_path = Path::new(CONFIG_DIR).join(&file_name);
|
||||||
|
|
||||||
match fs::write(&target_path, &req.config).await {
|
match fs::write(&target_path, &req.config).await {
|
||||||
@@ -1160,6 +1175,23 @@ async fn get_routes(State(state): State<HttpAppState>) -> Json<ApiResponse<Vec<H
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_normalize_config_file_name() {
|
||||||
|
// 无扩展名补 .toml
|
||||||
|
assert_eq!(
|
||||||
|
normalize_config_file_name("myconfig".to_string()).unwrap(),
|
||||||
|
"myconfig.toml"
|
||||||
|
);
|
||||||
|
// 已是 .toml 保持不变
|
||||||
|
assert_eq!(
|
||||||
|
normalize_config_file_name("a.toml".to_string()).unwrap(),
|
||||||
|
"a.toml"
|
||||||
|
);
|
||||||
|
// 其他扩展名拒绝(list_configs 只列 *.toml,保存了也不可见)
|
||||||
|
assert!(normalize_config_file_name("a.txt".to_string()).is_err());
|
||||||
|
assert!(normalize_config_file_name("a.json".to_string()).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_resolve_static_path_allows_normal_paths() {
|
fn test_resolve_static_path_allows_normal_paths() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
Reference in New Issue
Block a user