feat: 支持SSH密钥认证,REMOTE_KEY配置项

- 新增 _ssh_wrap 辅助函数:有key用key,有密码用sshpass,都没有走默认
- save_config 新增 REMOTE_KEY 字段
- setup 交互新增密钥路径提示
- sshpass 依赖改为可选(key认证不需要)
This commit is contained in:
mango
2026-02-22 00:02:42 +08:00
parent 79efc73897
commit 0ce006b6de

View File

@@ -54,7 +54,7 @@ install_deps() {
check_deps() {
local missing=""
command -v rsync &>/dev/null || missing+=" rsync"
command -v sshpass &>/dev/null || missing+=" sshpass"
# sshpass is optional when using key auth
command -v jq &>/dev/null || missing+=" jq"
if [ -n "$missing" ]; then
@@ -631,7 +631,7 @@ cleanup_remote() {
local remote_path="${REMOTE_DIR:-/backup}/${VPS_NAME:-$(hostname)}"
log "🧹 清理远程旧快照 (保留${days}天)..."
sshpass -p "$REMOTE_PASS" ssh -o StrictHostKeyChecking=no \
_ssh_wrap ssh -o StrictHostKeyChecking=no \
-p "${REMOTE_PORT:-22}" "${REMOTE_USER:-root}@$REMOTE_IP" \
"find $remote_path -name '*.tar.gz' -mtime +$days -delete 2>/dev/null" || true
}
@@ -883,7 +883,7 @@ do_restore_config_remote() {
echo ""
# 获取远程快照列表
local snap_list=$(sshpass -p "$REMOTE_PASS" ssh -o StrictHostKeyChecking=no \
local snap_list=$(_ssh_wrap ssh -o StrictHostKeyChecking=no \
-p "${REMOTE_PORT:-22}" "${REMOTE_USER:-root}@$REMOTE_IP" \
"ls -t $remote_path/*.tar.gz 2>/dev/null")
@@ -895,7 +895,7 @@ do_restore_config_remote() {
local snaps=()
while read -r snap; do
local name=$(basename "$snap")
local size=$(sshpass -p "$REMOTE_PASS" ssh -o StrictHostKeyChecking=no \
local size=$(_ssh_wrap ssh -o StrictHostKeyChecking=no \
-p "${REMOTE_PORT:-22}" "${REMOTE_USER:-root}@$REMOTE_IP" \
"ls -lh '$snap' 2>/dev/null | awk '{print \$5}'" 2>/dev/null)
echo " $i) $name ($size)"
@@ -916,7 +916,7 @@ do_restore_config_remote() {
log "下载快照: $(basename "$selected")"
local local_file="/tmp/remote_snapshot_$$.tar.gz"
sshpass -p "$REMOTE_PASS" scp -o StrictHostKeyChecking=no \
_ssh_wrap scp -o StrictHostKeyChecking=no \
-P "${REMOTE_PORT:-22}" "${REMOTE_USER:-root}@$REMOTE_IP:$selected" "$local_file"
[ ! -f "$local_file" ] && { error "下载失败"; return 1; }
@@ -1012,12 +1012,12 @@ do_sync_remote() {
log "📤 同步到远程: $REMOTE_IP:$remote_path"
# 创建远程目录以VPS名称命名
sshpass -p "$REMOTE_PASS" ssh -o StrictHostKeyChecking=no \
_ssh_wrap ssh -o StrictHostKeyChecking=no \
-p "${REMOTE_PORT:-22}" "${REMOTE_USER:-root}@$REMOTE_IP" \
"mkdir -p $remote_path"
# 同步到VPS专属目录
sshpass -p "$REMOTE_PASS" rsync -avz --progress \
_ssh_wrap rsync -avz --progress \
-e "ssh -o StrictHostKeyChecking=no -p ${REMOTE_PORT:-22}" \
"$latest" "${REMOTE_USER:-root}@$REMOTE_IP:$remote_path/"
@@ -1140,6 +1140,31 @@ load_config() {
[ -f "$CONFIG_FILE" ] && source "$CONFIG_FILE"
}
# SSH/SCP/rsync 前缀有key用key有密码用sshpass都没有走默认
_ssh_wrap() {
local mode="$1"; shift
local key="${REMOTE_KEY:-}" pass="${REMOTE_PASS:-}"
if [ -n "$key" ] && [ -f "$key" ]; then
case "$mode" in
ssh) ssh -i "$key" "$@" ;;
scp) scp -i "$key" "$@" ;;
rsync) rsync -e "ssh -i $key" "$@" ;;
esac
elif [ -n "$pass" ]; then
case "$mode" in
ssh) sshpass -p "$pass" ssh "$@" ;;
scp) sshpass -p "$pass" scp "$@" ;;
rsync) sshpass -p "$pass" rsync "$@" ;;
esac
else
case "$mode" in
ssh) ssh "$@" ;;
scp) scp "$@" ;;
rsync) rsync "$@" ;;
esac
fi
}
save_config() {
cat > "$CONFIG_FILE" << EOF
VPS_NAME="$VPS_NAME"
@@ -1149,6 +1174,7 @@ REMOTE_IP="$REMOTE_IP"
REMOTE_PORT="$REMOTE_PORT"
REMOTE_USER="$REMOTE_USER"
REMOTE_PASS="$REMOTE_PASS"
REMOTE_KEY="$REMOTE_KEY"
REMOTE_DIR="$REMOTE_DIR"
REMOTE_KEEP_DAYS="$REMOTE_KEEP_DAYS"
TG_BOT_TOKEN="$TG_BOT_TOKEN"
@@ -1179,8 +1205,9 @@ do_setup() {
REMOTE_PORT=${REMOTE_PORT:-22}
read -p "远程用户 [root]: " REMOTE_USER
REMOTE_USER=${REMOTE_USER:-root}
read -s -p "远程密码: " REMOTE_PASS
read -s -p "远程密码 (key认证留空): " REMOTE_PASS
echo ""
read -p "远程密钥路径 (密码认证留空): " REMOTE_KEY
read -p "远程目录 [/backup]: " REMOTE_DIR
REMOTE_DIR=${REMOTE_DIR:-/backup}
read -p "远程保留天数 [30]: " REMOTE_KEEP_DAYS