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
|
||||
[push]
|
||||
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 vs="vim ~/.vimrc"
|
||||
alias zs="vim ~/.zshrc"
|
||||
alias zr="exec $SHELL && . ~/.zshrc"
|
||||
alias zr="source ~/.zshrc"
|
||||
alias ll="ls -alh"
|
||||
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
|
||||
zstyle ':completion:*' menu select
|
||||
|
||||
@@ -75,9 +75,12 @@ fn plugin_add(name: &str) {
|
||||
let repo = name.rsplit('/').next().unwrap_or(name);
|
||||
let repo = repo.strip_suffix(".git").unwrap_or(repo);
|
||||
(name.to_string(), repo.to_string())
|
||||
} else {
|
||||
} else if name.contains('/') {
|
||||
let repo = name.split('/').last().unwrap_or(name);
|
||||
(format!("https://github.com/{}.git", name), repo.to_string())
|
||||
} else {
|
||||
eprintln!("usage: ais plugin add <user/repo>");
|
||||
return;
|
||||
};
|
||||
|
||||
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 entries = match std::fs::read_dir(&dir) {
|
||||
Ok(e) => e,
|
||||
Err(_) => {
|
||||
eprintln!("no plugins");
|
||||
return;
|
||||
}
|
||||
Err(_) => return vec![],
|
||||
};
|
||||
|
||||
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
|
||||
entries
|
||||
.flatten()
|
||||
.filter(|e| e.file_type().map(|t| t.is_dir()).unwrap_or(false))
|
||||
.map(|e| e.file_name().to_string_lossy().to_string())
|
||||
.filter(|n| !n.starts_with('.'))
|
||||
.collect();
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn plugin_ls() {
|
||||
let plugins = list_plugins();
|
||||
if plugins.is_empty() {
|
||||
eprintln!("no plugins");
|
||||
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") {
|
||||
Some(s) => s,
|
||||
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() {
|
||||
eprintln!("{} not found", target);
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user