audit(docs/28): Git 同步审计二轮——修复选项注入校验/默认 .gitignore/设置弹窗陈旧守卫,4 低项记录待办
This commit is contained in:
@@ -649,6 +649,38 @@ pub struct GitSyncOutcome {
|
||||
pub summary: String,
|
||||
}
|
||||
|
||||
/// 分支名校验(简化版 check-ref-format):用户输入会作为 git 命令参数,
|
||||
/// 以 - 开头会被解析成选项(选项注入),其余非法形态 git 自己也会拒绝。
|
||||
fn validate_branch(branch: &str) -> Result<String, String> {
|
||||
let b = branch.trim();
|
||||
if b.is_empty() {
|
||||
return Ok("main".to_string());
|
||||
}
|
||||
let bad = b.len() > 100
|
||||
|| b.starts_with('-')
|
||||
|| b.starts_with('.')
|
||||
|| b.ends_with('/')
|
||||
|| b.ends_with(".lock")
|
||||
|| b.contains("..")
|
||||
|| b.chars().any(|c| c.is_whitespace() || c.is_control() || "~^:?*[\\]".contains(c));
|
||||
if bad {
|
||||
return Err(format!("分支名不合法:{b}"));
|
||||
}
|
||||
Ok(b.to_string())
|
||||
}
|
||||
|
||||
/// 远程地址校验:不得以 - 开头(选项注入)、不得含空白/控制字符。
|
||||
fn validate_remote_url(url: &str) -> Result<String, String> {
|
||||
let u = url.trim();
|
||||
if u.is_empty() {
|
||||
return Ok(String::new());
|
||||
}
|
||||
if u.len() > 2000 || u.starts_with('-') || u.chars().any(|c| c.is_whitespace() || c.is_control()) {
|
||||
return Err("远程仓库地址不合法".to_string());
|
||||
}
|
||||
Ok(u.to_string())
|
||||
}
|
||||
|
||||
fn run_git(dir: &Path, args: &[&str]) -> Result<String, String> {
|
||||
let mut cmd = std::process::Command::new("git");
|
||||
cmd.args(args)
|
||||
@@ -738,10 +770,20 @@ pub async fn git_status(root: String) -> GitStatusInfo {
|
||||
pub async fn git_init_repo(root: String, remote_url: String, branch: String) -> Result<GitStatusInfo, String> {
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let dir = Path::new(&root);
|
||||
let b = if branch.trim().is_empty() { "main" } else { branch.trim() };
|
||||
run_git(dir, &["init", "-b", b])?;
|
||||
if !remote_url.trim().is_empty() {
|
||||
run_git(dir, &["remote", "add", "origin", remote_url.trim()])?;
|
||||
let b = validate_branch(&branch)?;
|
||||
let url = validate_remote_url(&remote_url)?;
|
||||
run_git(dir, &["init", "-b", &b])?;
|
||||
if !url.is_empty() {
|
||||
run_git(dir, &["remote", "add", "origin", &url])?;
|
||||
}
|
||||
// 同步会提交文件夹内全部未忽略文件:新建仓库时种一份保守的
|
||||
// .gitignore(系统垃圾、临时文件、.env),避免敏感/无用文件被推走
|
||||
let gitignore = dir.join(".gitignore");
|
||||
if !gitignore.exists() {
|
||||
let _ = std::fs::write(
|
||||
&gitignore,
|
||||
".DS_Store\nThumbs.db\ndesktop.ini\n*.tmp\n~$*\n.env\n.env.*\n",
|
||||
);
|
||||
}
|
||||
Ok(git_status_inner(&root))
|
||||
})
|
||||
@@ -753,7 +795,8 @@ pub async fn git_init_repo(root: String, remote_url: String, branch: String) ->
|
||||
pub async fn git_set_remote(root: String, remote_url: String) -> Result<GitStatusInfo, String> {
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let dir = Path::new(&root);
|
||||
let url = remote_url.trim();
|
||||
let url_owned = validate_remote_url(&remote_url)?;
|
||||
let url = url_owned.as_str();
|
||||
let has_origin = run_git(dir, &["remote"]).map(|r| r.lines().any(|l| l.trim() == "origin")).unwrap_or(false);
|
||||
if url.is_empty() {
|
||||
if has_origin {
|
||||
|
||||
Reference in New Issue
Block a user