security: fix path traversal in plugin_rm, add coding tools
- prevent path traversal in ais plugin rm (reject .. and /) - validate plugin_add requires user/repo format - extract list_plugins() helper to deduplicate code - add git aliases (s, d, l, lg, pa for dual push, etc) - add cargo/rg aliases and mkcd helper to zshrc - fix zr alias (source instead of unreachable exec)
This commit is contained in:
21
.gitconfig
21
.gitconfig
@@ -12,3 +12,24 @@
|
|||||||
defaultBranch = main
|
defaultBranch = main
|
||||||
[push]
|
[push]
|
||||||
autoSetupRemote = true
|
autoSetupRemote = true
|
||||||
|
[alias]
|
||||||
|
s = status -sb
|
||||||
|
d = diff
|
||||||
|
ds = diff --staged
|
||||||
|
l = log --oneline -20
|
||||||
|
lg = log --oneline --graph --all -30
|
||||||
|
a = add
|
||||||
|
cm = commit -m
|
||||||
|
co = checkout
|
||||||
|
br = branch -v
|
||||||
|
p = push
|
||||||
|
pa = !git push origin main && git push gitea main
|
||||||
|
f = fetch --all
|
||||||
|
last = log -1 --stat
|
||||||
|
undo = reset --soft HEAD~1
|
||||||
|
amend = commit --amend --no-edit
|
||||||
|
wip = !git add -A && git commit -m 'wip'
|
||||||
|
[diff]
|
||||||
|
colorMoved = default
|
||||||
|
[merge]
|
||||||
|
conflictstyle = diff3
|
||||||
|
|||||||
16
.zshrc
16
.zshrc
@@ -12,9 +12,23 @@ alias v="vim"
|
|||||||
alias ts="vim ~/.tmux.conf"
|
alias ts="vim ~/.tmux.conf"
|
||||||
alias vs="vim ~/.vimrc"
|
alias vs="vim ~/.vimrc"
|
||||||
alias zs="vim ~/.zshrc"
|
alias zs="vim ~/.zshrc"
|
||||||
alias zr="exec $SHELL && . ~/.zshrc"
|
alias zr="source ~/.zshrc"
|
||||||
alias ll="ls -alh"
|
alias ll="ls -alh"
|
||||||
alias df="df -H"
|
alias df="df -H"
|
||||||
|
alias g="git"
|
||||||
|
alias gs="git s"
|
||||||
|
alias gd="git d"
|
||||||
|
alias gl="git l"
|
||||||
|
alias gp="git pa"
|
||||||
|
alias cb="cargo build --release"
|
||||||
|
alias cr="cargo run"
|
||||||
|
alias ct="cargo test"
|
||||||
|
|
||||||
|
# mkcd: create and enter directory
|
||||||
|
mkcd() { mkdir -p "$1" && cd "$1" }
|
||||||
|
|
||||||
|
# rg shortcut with common defaults
|
||||||
|
r() { rg --smart-case --hidden --glob '!.git' "$@" }
|
||||||
|
|
||||||
zmodload zsh/complist
|
zmodload zsh/complist
|
||||||
zstyle ':completion:*' menu select
|
zstyle ':completion:*' menu select
|
||||||
|
|||||||
@@ -75,9 +75,12 @@ fn plugin_add(name: &str) {
|
|||||||
let repo = name.rsplit('/').next().unwrap_or(name);
|
let repo = name.rsplit('/').next().unwrap_or(name);
|
||||||
let repo = repo.strip_suffix(".git").unwrap_or(repo);
|
let repo = repo.strip_suffix(".git").unwrap_or(repo);
|
||||||
(name.to_string(), repo.to_string())
|
(name.to_string(), repo.to_string())
|
||||||
} else {
|
} else if name.contains('/') {
|
||||||
let repo = name.split('/').last().unwrap_or(name);
|
let repo = name.split('/').last().unwrap_or(name);
|
||||||
(format!("https://github.com/{}.git", name), repo.to_string())
|
(format!("https://github.com/{}.git", name), repo.to_string())
|
||||||
|
} else {
|
||||||
|
eprintln!("usage: ais plugin add <user/repo>");
|
||||||
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let dest = format!("{}/{}", dir, repo_name);
|
let dest = format!("{}/{}", dir, repo_name);
|
||||||
@@ -97,59 +100,53 @@ fn plugin_add(name: &str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn plugin_ls() {
|
fn list_plugins() -> Vec<String> {
|
||||||
let dir = plugin_dir();
|
let dir = plugin_dir();
|
||||||
let entries = match std::fs::read_dir(&dir) {
|
let entries = match std::fs::read_dir(&dir) {
|
||||||
Ok(e) => e,
|
Ok(e) => e,
|
||||||
Err(_) => {
|
Err(_) => return vec![],
|
||||||
eprintln!("no plugins");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
entries
|
||||||
for entry in entries.flatten() {
|
|
||||||
if entry.file_type().map(|t| t.is_dir()).unwrap_or(false) {
|
|
||||||
let name = entry.file_name().to_string_lossy().to_string();
|
|
||||||
if !name.starts_with('.') {
|
|
||||||
println!("{}", name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn plugin_rm(name: Option<&str>) {
|
|
||||||
let dir = plugin_dir();
|
|
||||||
|
|
||||||
let target = if let Some(n) = name {
|
|
||||||
n.to_string()
|
|
||||||
} else {
|
|
||||||
// fuzzy select from installed plugins
|
|
||||||
let entries = match std::fs::read_dir(&dir) {
|
|
||||||
Ok(e) => e,
|
|
||||||
Err(_) => {
|
|
||||||
eprintln!("no plugins");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let plugins: Vec<String> = entries
|
|
||||||
.flatten()
|
.flatten()
|
||||||
.filter(|e| e.file_type().map(|t| t.is_dir()).unwrap_or(false))
|
.filter(|e| e.file_type().map(|t| t.is_dir()).unwrap_or(false))
|
||||||
.map(|e| e.file_name().to_string_lossy().to_string())
|
.map(|e| e.file_name().to_string_lossy().to_string())
|
||||||
.filter(|n| !n.starts_with('.'))
|
.filter(|n| !n.starts_with('.'))
|
||||||
.collect();
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn plugin_ls() {
|
||||||
|
let plugins = list_plugins();
|
||||||
if plugins.is_empty() {
|
if plugins.is_empty() {
|
||||||
eprintln!("no plugins");
|
eprintln!("no plugins");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
for name in &plugins {
|
||||||
|
println!("{}", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn plugin_rm(name: Option<&str>) {
|
||||||
|
let target = if let Some(n) = name {
|
||||||
|
n.to_string()
|
||||||
|
} else {
|
||||||
|
let plugins = list_plugins();
|
||||||
|
if plugins.is_empty() {
|
||||||
|
eprintln!("no plugins");
|
||||||
|
return;
|
||||||
|
}
|
||||||
match fuzzy_select(&plugins, "rm plugin") {
|
match fuzzy_select(&plugins, "rm plugin") {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => return,
|
None => return,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let path = format!("{}/{}", dir, target);
|
// prevent path traversal
|
||||||
|
if target.contains('/') || target.contains("..") {
|
||||||
|
eprintln!("invalid plugin name: {}", target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = format!("{}/{}", plugin_dir(), target);
|
||||||
if !std::path::Path::new(&path).exists() {
|
if !std::path::Path::new(&path).exists() {
|
||||||
eprintln!("{} not found", target);
|
eprintln!("{} not found", target);
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user