fix remote auth and danger guard
This commit is contained in:
1 parent
2fa77e3ef7
commit
e35a20bceb
2 files changed
+174
-28
No files matched your search
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "autodl-remote",
|
||||
"version": "0.6.0",
|
||||
"version": "0.6.1",
|
||||
"description": "Bash-only SSH account, command, upload, download, job, and shutdown tool layer for AutoDL.",
|
||||
"author": {
|
||||
"name": "haibarazz",
|
||||
|
||||
@@ -305,6 +305,15 @@ ssh_common_args() {
|
||||
fi
|
||||
}
|
||||
|
||||
scp_common_args() {
|
||||
SCP_ARGS=(-P "$ACCOUNT_PORT" -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -o ControlMaster=auto -o ControlPersist=600 -o "ControlPath=$APP_DIR/ssh-%C")
|
||||
mkdir -p "$APP_DIR"
|
||||
[ -n "$ACCOUNT_KEY" ] && SCP_ARGS+=(-i "$ACCOUNT_KEY")
|
||||
if [ "$ACCOUNT_AUTH" != "keychain" ] && [ "$ACCOUNT_AUTH" != "prompt" ]; then
|
||||
SCP_ARGS+=(-o BatchMode=yes)
|
||||
fi
|
||||
}
|
||||
|
||||
rsync_ssh_command() {
|
||||
local cmd
|
||||
cmd="ssh -p $(shell_quote "$ACCOUNT_PORT") -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -o ControlMaster=auto -o ControlPersist=600 -o ControlPath=$(shell_quote "$APP_DIR/ssh-%C")"
|
||||
@@ -324,7 +333,7 @@ expect_with_password() {
|
||||
command -v expect >/dev/null 2>&1 || die "Account uses keychain auth, but expect is not available."
|
||||
local password="$1"
|
||||
shift
|
||||
AUTODL_REMOTE_PASSWORD="$password" expect -c '
|
||||
AUTODL_REMOTE_PASSWORD="$password" expect -f /dev/stdin "$@" <<'EXPECT'
|
||||
set timeout -1
|
||||
set password $env(AUTODL_REMOTE_PASSWORD)
|
||||
spawn {*}$argv
|
||||
@@ -341,7 +350,7 @@ expect_with_password() {
|
||||
}
|
||||
catch wait result
|
||||
exit [lindex $result 3]
|
||||
' "$@"
|
||||
EXPECT
|
||||
}
|
||||
|
||||
run_transport() {
|
||||
@@ -423,19 +432,151 @@ upload_local_file() {
|
||||
local local_path="$1" remote_path="$2"
|
||||
[ -f "$local_path" ] || die "Local script does not exist or is not a file: $local_path"
|
||||
ensure_remote_dir "$(dirname "$remote_path")"
|
||||
scp_common_args
|
||||
run_transport scp "${SCP_ARGS[@]}" "$local_path" "$ACCOUNT_TARGET:$remote_path"
|
||||
}
|
||||
|
||||
upload_stdin_to_remote() {
|
||||
local remote_path="$1"
|
||||
ensure_remote_dir "$(dirname "$remote_path")"
|
||||
ssh_common_args
|
||||
local scp_args=(-P "$ACCOUNT_PORT")
|
||||
[ -n "$ACCOUNT_KEY" ] && scp_args+=(-i "$ACCOUNT_KEY")
|
||||
run_transport scp "${scp_args[@]}" "$local_path" "$ACCOUNT_TARGET:$remote_path"
|
||||
run_transport ssh "${SSH_ARGS[@]}" "$ACCOUNT_TARGET" "cat > $(shell_quote "$remote_path")"
|
||||
}
|
||||
|
||||
upload_file_via_ssh() {
|
||||
local local_path="$1" remote_path="$2"
|
||||
[ -f "$local_path" ] || die "Local script does not exist or is not a file: $local_path"
|
||||
upload_stdin_to_remote "$remote_path" < "$local_path"
|
||||
}
|
||||
|
||||
strip_token_quotes() {
|
||||
local value="$1"
|
||||
value="${value%\"}"
|
||||
value="${value#\"}"
|
||||
value="${value%\'}"
|
||||
value="${value#\'}"
|
||||
printf '%s\n' "$value"
|
||||
}
|
||||
|
||||
is_dangerous_rm_target() {
|
||||
local target="$1" recursive="$2" cwd="${3:-$REMOTE_ROOT}" project_root autodl_tmp
|
||||
target="$(strip_token_quotes "$target")"
|
||||
[ -n "$target" ] || return 1
|
||||
|
||||
project_root="${REMOTE_ROOT%/}"
|
||||
autodl_tmp="/root/autodl-tmp"
|
||||
|
||||
case "$target" in
|
||||
"\$REMOTE_ROOT"|"\${REMOTE_ROOT}"|"\$PWD"|"\${PWD}") return 0 ;;
|
||||
esac
|
||||
|
||||
[ "$target" = "/" ] && return 0
|
||||
[ "$target" = "/*" ] && return 0
|
||||
|
||||
if [ "$recursive" = "true" ]; then
|
||||
case "$target" in
|
||||
"."|"./"|"./*"|"*"|"~"|"~/"|"~/*") return 0 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
while [ "${target%/}" != "$target" ] && [ "$target" != "/" ]; do
|
||||
target="${target%/}"
|
||||
done
|
||||
|
||||
if [ "$target" = "$project_root" ]; then
|
||||
return 0
|
||||
fi
|
||||
if [ "$target" = "$project_root/*" ]; then
|
||||
return 0
|
||||
fi
|
||||
if [ "$target" = "$autodl_tmp" ] || [ "$target" = "$autodl_tmp/*" ]; then
|
||||
return 0
|
||||
fi
|
||||
if [ "$recursive" = "true" ] && [ "$target" = "$cwd" ]; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
contains_dangerous_rm() {
|
||||
local cmd="$1" cwd="${2:-$REMOTE_ROOT}" line token recursive
|
||||
while IFS= read -r line; do
|
||||
set -- $line
|
||||
while [ $# -gt 0 ]; do
|
||||
token="$(strip_token_quotes "$1")"
|
||||
case "$token" in
|
||||
sudo|command|builtin|nohup) shift ;;
|
||||
env) shift; while [ $# -gt 0 ]; do case "$1" in *=*) shift ;; *) break ;; esac; done ;;
|
||||
*=*) shift ;;
|
||||
*) break ;;
|
||||
esac
|
||||
done
|
||||
token="$(strip_token_quotes "${1:-}")"
|
||||
[ "${token##*/}" = "rm" ] || continue
|
||||
shift
|
||||
recursive=false
|
||||
while [ $# -gt 0 ]; do
|
||||
token="$1"
|
||||
shift
|
||||
case "$token" in
|
||||
--) break ;;
|
||||
--*) continue ;;
|
||||
-*) case "$token" in *r*|*R*) recursive=true ;; esac; continue ;;
|
||||
esac
|
||||
is_dangerous_rm_target "$token" "$recursive" "$cwd" && return 0
|
||||
done
|
||||
while [ $# -gt 0 ]; do
|
||||
token="$1"
|
||||
shift
|
||||
is_dangerous_rm_target "$token" "$recursive" "$cwd" && return 0
|
||||
done
|
||||
done <<EOF
|
||||
$(printf '%s\n' "$cmd" | sed 's/[;&|]/\
|
||||
/g')
|
||||
EOF
|
||||
return 1
|
||||
}
|
||||
|
||||
contains_dangerous_system_command() {
|
||||
local cmd="$1" line token command_name
|
||||
while IFS= read -r line; do
|
||||
set -- $line
|
||||
while [ $# -gt 0 ]; do
|
||||
token="$(strip_token_quotes "$1")"
|
||||
case "$token" in
|
||||
sudo|command|builtin|nohup) shift ;;
|
||||
env) shift; while [ $# -gt 0 ]; do case "$1" in *=*) shift ;; *) break ;; esac; done ;;
|
||||
*=*) shift ;;
|
||||
*) break ;;
|
||||
esac
|
||||
done
|
||||
[ $# -gt 0 ] || continue
|
||||
token="$(strip_token_quotes "$1")"
|
||||
command_name="${token##*/}"
|
||||
case "$command_name" in
|
||||
shutdown|reboot|poweroff|halt|mkfs|mkfs.*)
|
||||
return 0
|
||||
;;
|
||||
dd)
|
||||
shift
|
||||
while [ $# -gt 0 ]; do
|
||||
token="$(strip_token_quotes "$1")"
|
||||
case "$token" in if=*) return 0 ;; esac
|
||||
shift
|
||||
done
|
||||
;;
|
||||
esac
|
||||
done <<EOF
|
||||
$(printf '%s\n' "$cmd" | sed 's/[;&|]/\
|
||||
/g')
|
||||
EOF
|
||||
return 1
|
||||
}
|
||||
|
||||
dangerous_command_check() {
|
||||
local cmd="$1"
|
||||
case "$cmd" in
|
||||
*"rm -rf /"*|*"mkfs"*|*"shutdown"*|*"reboot"*|*"poweroff"*|*"dd if="*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
local cmd="$1" cwd="${2:-$REMOTE_ROOT}"
|
||||
contains_dangerous_system_command "$cmd" && return 1
|
||||
contains_dangerous_rm "$cmd" "$cwd" && return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -659,7 +800,11 @@ cmd_exec() {
|
||||
local_script="$(local_join "$script")"
|
||||
tmp_name="$(date +%Y%m%d-%H%M%S)-$(basename "$script" | sed 's/[^A-Za-z0-9_.-]/-/g')"
|
||||
remote_script="$REMOTE_ROOT/.autodl-remote/tmp/$tmp_name"
|
||||
upload_local_file "$local_script" "$remote_script"
|
||||
if [ "$ACCOUNT_AUTH" = "keychain" ]; then
|
||||
upload_local_file "$local_script" "$remote_script" || return 1
|
||||
else
|
||||
upload_file_via_ssh "$local_script" "$remote_script" || return 1
|
||||
fi
|
||||
if [ $# -gt 0 ]; then
|
||||
cmd="$* $(shell_quote "$remote_script")"
|
||||
else
|
||||
@@ -667,13 +812,17 @@ cmd_exec() {
|
||||
fi
|
||||
elif [ "$stdin_mode" = "true" ]; then
|
||||
[ $# -gt 0 ] || die "exec --stdin requires a command after --, for example: exec --stdin -- bash"
|
||||
local tmp_local
|
||||
tmp_local="$(mktemp "${TMPDIR:-/tmp}/autodl-remote-stdin.XXXXXX")" || die "mktemp failed"
|
||||
cat > "$tmp_local"
|
||||
tmp_name="$(date +%Y%m%d-%H%M%S)-stdin.sh"
|
||||
remote_script="$REMOTE_ROOT/.autodl-remote/tmp/$tmp_name"
|
||||
upload_local_file "$tmp_local" "$remote_script"
|
||||
rm -f "$tmp_local"
|
||||
if [ "$ACCOUNT_AUTH" = "keychain" ]; then
|
||||
local tmp_local
|
||||
tmp_local="$(mktemp "${TMPDIR:-/tmp}/autodl-remote-stdin.XXXXXX")" || die "mktemp failed"
|
||||
cat > "$tmp_local"
|
||||
upload_local_file "$tmp_local" "$remote_script" || { rm -f "$tmp_local"; return 1; }
|
||||
rm -f "$tmp_local"
|
||||
else
|
||||
upload_stdin_to_remote "$remote_script" || return 1
|
||||
fi
|
||||
cmd="$* < $(shell_quote "$remote_script")"
|
||||
else
|
||||
[ $# -gt 0 ] || die "exec requires a command"
|
||||
@@ -681,7 +830,7 @@ cmd_exec() {
|
||||
fi
|
||||
|
||||
if [ "$allow_dangerous" != "true" ]; then
|
||||
dangerous_command_check "$cmd" || die "Dangerous remote command blocked. Re-run with --allow-dangerous after explicit approval."
|
||||
dangerous_command_check "$cmd" "$cwd" || die "Dangerous remote command blocked. Re-run with --allow-dangerous after explicit approval."
|
||||
fi
|
||||
[ -n "$name" ] || name="exec-$(date +%Y%m%d-%H%M%S)"
|
||||
name="$(sanitize_name "$name")"
|
||||
@@ -739,13 +888,11 @@ cmd_put() {
|
||||
fi
|
||||
else
|
||||
[ "$dry_run" != "true" ] || die "dry-run requires rsync."
|
||||
ssh_common_args
|
||||
local scp_args=(-P "$ACCOUNT_PORT")
|
||||
[ -n "$ACCOUNT_KEY" ] && scp_args+=(-i "$ACCOUNT_KEY")
|
||||
scp_common_args
|
||||
if [ -d "$local_path" ]; then
|
||||
run_transport scp -r "${scp_args[@]}" "$local_path" "$ACCOUNT_TARGET:$remote_path"
|
||||
run_transport scp -r "${SCP_ARGS[@]}" "$local_path" "$ACCOUNT_TARGET:$remote_path"
|
||||
else
|
||||
run_transport scp "${scp_args[@]}" "$local_path" "$ACCOUNT_TARGET:$remote_path"
|
||||
run_transport scp "${SCP_ARGS[@]}" "$local_path" "$ACCOUNT_TARGET:$remote_path"
|
||||
fi
|
||||
fi
|
||||
write_history put "$local_arg -> $remote_path"
|
||||
@@ -785,12 +932,11 @@ cmd_get() {
|
||||
fi
|
||||
else
|
||||
[ "$dry_run" != "true" ] || die "dry-run requires rsync."
|
||||
local scp_args=(-P "$ACCOUNT_PORT")
|
||||
[ -n "$ACCOUNT_KEY" ] && scp_args+=(-i "$ACCOUNT_KEY")
|
||||
scp_common_args
|
||||
if [ "$kind" = "dir" ]; then
|
||||
run_transport scp -r "${scp_args[@]}" "$ACCOUNT_TARGET:$remote_path" "$local_path"
|
||||
run_transport scp -r "${SCP_ARGS[@]}" "$ACCOUNT_TARGET:$remote_path" "$local_path"
|
||||
else
|
||||
run_transport scp "${scp_args[@]}" "$ACCOUNT_TARGET:$remote_path" "$local_path"
|
||||
run_transport scp "${SCP_ARGS[@]}" "$ACCOUNT_TARGET:$remote_path" "$local_path"
|
||||
fi
|
||||
fi
|
||||
write_history get "$remote_path -> $local_arg"
|
||||
|
||||
Reference in new issue
Block a user