Files
leefer 199b46b593 修复:向导认证成功后卡死、配置不持久化
根因:非 Windows 走 keyring 加密,无桌面环境的服务器上 keyring 后端不可用,
保存时抛异常/挂起 → 第2步不出现且配置未落盘。
- storage: 非 Windows 改为明文保存 + 文件权限 600(与 ~/.ssh 私钥同级),不再依赖 keyring
- cli: 顶层异常兜底(打印堆栈,不再无声退出);向导显示配置文件路径
- 兼容读取旧 kr: 前缀配置;install.sh 去掉 keyring 依赖
2026-09-27 20:24:01 +08:00

142 lines
4.8 KiB
Bash

#!/usr/bin/env bash
# SSH 隧道管理器 一键安装(Linux / macOS)
# 用法: curl -fsSL https://gitea.xbay.cc/leefer/ssh-e2e/raw/branch/main/install.sh | bash
set -euo pipefail
BASE_URL="https://gitea.xbay.cc/leefer/ssh-e2e"
APP_DIR="$HOME/ssh-e2e"
BIN_DIR="$HOME/.local/bin"
say() { printf '\033[1;32m==>\033[0m %s\n' "$*"; }
die() { printf '\033[1;31m错误:\033[0m %s\n' "$*" >&2; exit 1; }
[ "$(uname)" = "Linux" ] || [ "$(uname)" = "Darwin" ] || die "此脚本仅支持 Linux / macOS"
# ---------- 系统包管理器 ----------
PKG_MGR=""
for m in apt-get dnf yum zypper pacman apk; do
command -v "$m" >/dev/null 2>&1 && { PKG_MGR="$m"; break; }
done
as_root() {
if [ "$(id -u)" = 0 ]; then "$@"
elif command -v sudo >/dev/null 2>&1; then sudo "$@"
else die "需要 root 权限但未找到 sudo,请手动安装后重试"; fi
}
# 各发行版补齐 python3+venv 所需的包
py_pkgs() {
case "$PKG_MGR" in
apt-get) echo "python3 python3-venv" ;;
dnf|yum) echo "python3 python3-pip" ;;
zypper) echo "python3 python3-pip" ;;
pacman) echo "python python-pip" ;;
apk) echo "python3 py3-pip py3-virtualenv" ;;
*) echo "" ;;
esac
}
pkg_install() {
[ -n "$PKG_MGR" ] || return 1
say "自动安装系统依赖($PKG_MGR): $* — 可能要求输入密码"
case "$PKG_MGR" in
apt-get) as_root apt-get update -qq >/dev/null 2>&1 || true; as_root apt-get install -y "$@" ;;
dnf) as_root dnf install -y -q "$@" ;;
yum) as_root yum install -y -q "$@" ;;
zypper) as_root zypper --non-interactive install "$@" ;;
pacman) as_root pacman -S --noconfirm --needed "$@" ;;
apk) as_root apk add "$@" ;;
esac
}
# ---------- Python 检查 + 自动补齐 ----------
ensure_python() {
if ! command -v python3 >/dev/null 2>&1; then
say "未找到 python3,尝试自动安装 ..."
pkgs="$(py_pkgs)"
[ -n "$pkgs" ] || die "未识别到包管理器,请手动安装 Python 3.10+ 后重试"
pkg_install $pkgs || die "自动安装 Python 失败,请手动安装后重试"
command -v python3 >/dev/null 2>&1 || die "python3 仍不可用,请手动安装"
fi
local pyver
pyver=$(python3 -c 'import sys;print("%d.%d"%sys.version_info[:2])')
case "$pyver" in
3.1[0-9]|3.[2-9][0-9]|[4-9].*) ;;
*) die "需要 Python 3.10+,当前 $pyver" ;;
esac
}
ensure_venv() {
if python3 -c "import ensurepip" >/dev/null 2>&1; then return 0; fi
say "系统 Python 缺少 venv/ensurepip 组件,尝试自动安装 ..."
pkgs="$(py_pkgs)"
[ -n "$pkgs" ] || die "当前平台无包管理器可自动补齐(如 macOS 可执行: xcode-select --install 或 brew install python)"
pkg_install $pkgs || die "自动安装 venv 组件失败,请手动执行后重试"
python3 -c "import ensurepip" >/dev/null 2>&1 \
|| die "venv 组件仍未就绪,请手动安装(Debian/Ubuntu: sudo apt install python3-venv)"
}
ensure_python
ensure_venv
# ---------- 下载源码 ----------
say "下载最新代码到 $APP_DIR ..."
mkdir -p "$APP_DIR"
if command -v git >/dev/null 2>&1; then
if [ -d "$APP_DIR/.git" ]; then
git -C "$APP_DIR" fetch --all --quiet && git -C "$APP_DIR" reset --hard origin/main --quiet
else
git clone --depth 1 "$BASE_URL.git" "$APP_DIR" 2>/dev/null || true
fi
fi
if [ ! -f "$APP_DIR/cli.py" ]; then
# git 不可用或克隆失败:直接拉归档
archive_url="$BASE_URL/archive/main.tar.gz"
if command -v curl >/dev/null 2>&1; then
curl -fsSL "$archive_url" | tar -xz -C "$APP_DIR" --strip-components 1
else
wget -qO- "$archive_url" | tar -xz -C "$APP_DIR" --strip-components 1
fi
fi
[ -f "$APP_DIR/cli.py" ] || die "代码下载失败,请检查网络后重试"
# ---------- 虚拟环境(不完整则整体重建) ----------
if [ ! -f "$APP_DIR/.venv/deps-done" ]; then
rm -rf "$APP_DIR/.venv"
say "创建虚拟环境并安装依赖(首次约 1-2 分钟)..."
python3 -m venv "$APP_DIR/.venv" || {
rm -rf "$APP_DIR/.venv"
die "虚拟环境创建失败(Debian/Ubuntu 可执行: sudo apt install python3-venv)"
}
"$APP_DIR/.venv/bin/pip" install --quiet --disable-pip-version-check \
paramiko cryptography > /dev/null
touch "$APP_DIR/.venv/deps-done"
fi
# ---------- ssh-tunnel 命令 ----------
mkdir -p "$BIN_DIR"
cat > "$BIN_DIR/ssh-tunnel" << EOF
#!/usr/bin/env bash
exec "$APP_DIR/.venv/bin/python" "$APP_DIR/cli.py" "\$@"
EOF
chmod +x "$BIN_DIR/ssh-tunnel"
# PATH 提示
case ":$PATH:" in
*":$BIN_DIR:"*) ;;
*)
shell_rc="$HOME/.bashrc"
[ "$(uname)" = "Darwin" ] && [ -f "$HOME/.zshrc" ] && shell_rc="$HOME/.zshrc"
grep -q 'ssh-e2e' "$shell_rc" 2>/dev/null || {
echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$shell_rc"
export PATH="$BIN_DIR:$PATH"
}
;;
esac
say "安装完成!正在进入配置向导 ..."
echo
# curl|bash 时 stdin 是管道,交互输入从终端(/dev/tty)读
exec "$BIN_DIR/ssh-tunnel" < /dev/tty