mirror of
https://gitee.com/samwaf/SamWaf.git
synced 2026-10-30 17:51:44 +08:00
ci:update install_samwaf.sh
This commit is contained in:
+449
-76
@@ -1,4 +1,32 @@
|
||||
#!/bin/bash
|
||||
# ==============================================================================
|
||||
# SamWaf 安装 / 更新 / 卸载脚本
|
||||
#
|
||||
# 特性:
|
||||
# 1. 多下载源自动测速择优(官方 update.samwaf.com / GitHub / Gitee)
|
||||
# 2. 跨源一致性完整性校验(防止下载到被篡改或过期的可执行文件)
|
||||
#
|
||||
# 安全校验模型(默认 consensus 跨源一致性):
|
||||
# · 官方来源(update.samwaf.com,算 1 个主机):
|
||||
# - /latest/latest.json → 该版本发布包(tar.gz)的权威 SHA256(正式版稳定通道);
|
||||
# - /samwaf_update/<plat>.json → 该版本可执行文件的权威 SHA256(App 自升级同端点)。
|
||||
# · 跨源佐证:从 GitHub 与 Gitee 拉取 checksums.txt,取同一发布包的 SHA256。
|
||||
# · 一致性:官方latest / GitHub / Gitee 三者对同一压缩包给出的 SHA256 必须完全一致,
|
||||
# 任一不一致即判定源污染并中止;并要求至少两个「相互独立的主机」为发布物背书。
|
||||
# · 最终安装的可执行文件:压缩包 SHA256 == 跨源一致值;若拿到官方二进制锚点,
|
||||
# 解包后的可执行文件 SHA256 还须 == 该锚点。
|
||||
# 注:update.samwaf.com/latest 现由 sync_release_go 保鲜,提供与 GitHub/Gitee 逐字节
|
||||
# 相同的版本化压缩包;latest.json 不可用时自动回退到 samwaf_update/<ver>/<plat>.gz。
|
||||
# 无论从哪个镜像下载,过期或被篡改的文件都会被拒绝并自动切换下一个源。
|
||||
#
|
||||
# 环境变量(可选):
|
||||
# SAMWAF_SOURCE=official|github|gitee 强制指定下载源,跳过测速
|
||||
# SAMWAF_VERIFY=consensus|anchor 校验强度(默认 consensus;anchor 仅用官方清单)
|
||||
# SAMWAF_INSECURE_TLS=1 关闭 TLS 证书校验(仅限老旧系统,内容仍有哈希校验)
|
||||
#
|
||||
# 说明:Atomgit(https://atomgit.com/SamSafe/SamWaf)的发布包下载需要登录鉴权,
|
||||
# 无法匿名脚本下载,故不参与自动测速,仅作为手动下载链接展示。
|
||||
# ==============================================================================
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
LANG=en_US.UTF-8
|
||||
@@ -8,33 +36,396 @@ NC='\033[0m' # 重置颜色
|
||||
GREEN='\033[0;32m' # 成功
|
||||
RED='\033[0;31m' # 错误
|
||||
BLUE='\033[0;34m' # 信息
|
||||
YELLOW='\033[0;33m' # 警告
|
||||
|
||||
# 检查是否为root权限
|
||||
log_info() { echo -e "${BLUE}$*${NC}"; }
|
||||
log_ok() { echo -e "${GREEN}$*${NC}"; }
|
||||
log_warn() { echo -e "${YELLOW}$*${NC}"; }
|
||||
log_err() { echo -e "${RED}$*${NC}"; }
|
||||
|
||||
# 检查是否为root权限
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo -e "\033[0;33m🔐 检测到未使用 root 权限,尝试使用 sudo 重新运行...\033[0m"
|
||||
exec sudo bash "$0" "$@"
|
||||
echo -e "${YELLOW}🔐 检测到未使用 root 权限,尝试使用 sudo 重新运行...${NC}"
|
||||
exec sudo -E bash "$0" "$@"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 获取当前脚本所在目录,在此目录下创建SamWaf目录
|
||||
# ------------------------------------------------------------------ 常量与全局
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
setup_path="${SCRIPT_DIR}/SamWaf"
|
||||
ARCH=$(uname -m)
|
||||
|
||||
# 初始化架构与执行文件名
|
||||
function init_arch_exec() {
|
||||
if [[ "$ARCH" == "x86_64" ]]; then
|
||||
exec_name="SamWafLinux64"
|
||||
url="https://update.samwaf.com/latest/SamWaf_Linux_x86_64.tar.gz"
|
||||
elif [[ "$ARCH" == "aarch64" ]] || [[ "$ARCH" == "arm64" ]]; then
|
||||
exec_name="SamWafLinuxArm64"
|
||||
url="https://update.samwaf.com/latest/SamWaf_Linux_arm64.tar.gz"
|
||||
else
|
||||
echo -e "${RED}❌ 不支持的架构: $ARCH${NC}"
|
||||
OFFICIAL_BASE="https://update.samwaf.com"
|
||||
GITHUB_BASE="https://github.com/samwafgo/SamWaf"
|
||||
GITEE_BASE="https://gitee.com/samwaf/SamWaf"
|
||||
ATOMGIT_PAGE="https://atomgit.com/SamSafe/SamWaf"
|
||||
|
||||
# 运行期变量(由各函数填充)
|
||||
EXEC_NAME="" # 可执行文件名 SamWafLinux64 / SamWafLinuxArm64
|
||||
PLAT_JSON="" # linux-amd64 / linux-arm64
|
||||
OS_ARCH="" # Linux_x86_64 / Linux_arm64(发布包命名用)
|
||||
VERSION="" # 例如 v1.3.22
|
||||
MANIFEST_BIN_SHA="" # samwaf_update 清单中的可执行文件 SHA256(hex)
|
||||
L_TAR_SHA="" # /latest/latest.json 中本平台压缩包 SHA256(hex)
|
||||
LATEST_JSON_OK=0 # /latest/latest.json 是否可用(官方稳定通道已保鲜)
|
||||
CK_TAR_SHA="" # 跨源一致的发布压缩包 SHA256(hex)
|
||||
CONSENSUS_HOSTS=0 # 提供一致压缩包校验和的来源数量(官方latest/GitHub/Gitee)
|
||||
GH_CK_OK=0 # GitHub checksums 是否可用
|
||||
GT_CK_OK=0 # Gitee checksums 是否可用
|
||||
VERIFIED_BIN="" # 校验通过的可执行文件路径
|
||||
USED_SOURCE="" # 实际使用的下载源
|
||||
USED_BIN_SHA="" # 实际安装的二进制 SHA256
|
||||
|
||||
VERIFY_MODE="${SAMWAF_VERIFY:-consensus}"
|
||||
FORCE_SOURCE="${SAMWAF_SOURCE:-}"
|
||||
WORKDIR=""
|
||||
|
||||
have() { command -v "$1" >/dev/null 2>&1; }
|
||||
|
||||
cleanup() { [ -n "$WORKDIR" ] && rm -rf "$WORKDIR" 2>/dev/null; }
|
||||
trap cleanup EXIT
|
||||
|
||||
# 依赖检查
|
||||
function check_deps() {
|
||||
local missing=""
|
||||
have tar || missing="$missing tar"
|
||||
have gzip || missing="$missing gzip"
|
||||
if ! have curl && ! have wget; then missing="$missing curl/wget"; fi
|
||||
if ! have sha256sum && ! have shasum && ! have openssl; then missing="$missing sha256sum/openssl"; fi
|
||||
if ! have base64; then missing="$missing base64"; fi
|
||||
if [ -n "$missing" ]; then
|
||||
log_err "❌ 缺少必要依赖:$missing,请先安装后重试"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 下载:DL <url> <outfile> (跟随重定向 + 重试;保持 TLS 校验,除非显式关闭)
|
||||
function DL() {
|
||||
local url="$1" out="$2" insecure=""
|
||||
[ "$SAMWAF_INSECURE_TLS" = "1" ] && insecure="1"
|
||||
if have curl; then
|
||||
if [ -n "$insecure" ]; then
|
||||
curl -fsSL -k --connect-timeout 10 --max-time 900 --retry 2 -o "$out" "$url"
|
||||
else
|
||||
curl -fsSL --connect-timeout 10 --max-time 900 --retry 2 -o "$out" "$url"
|
||||
fi
|
||||
else
|
||||
if [ -n "$insecure" ]; then
|
||||
wget --no-check-certificate -q --tries=3 --timeout=900 -O "$out" "$url"
|
||||
else
|
||||
wget -q --tries=3 --timeout=900 -O "$out" "$url"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# 计算文件 SHA256(hex)
|
||||
function sha256_of() {
|
||||
if have sha256sum; then sha256sum "$1" | awk '{print $1}';
|
||||
elif have shasum; then shasum -a 256 "$1" | awk '{print $1}';
|
||||
else openssl dgst -sha256 "$1" | awk '{print $NF}'; fi
|
||||
}
|
||||
|
||||
# base64 → hex
|
||||
function b64_to_hex() {
|
||||
if have od; then
|
||||
printf '%s' "$1" | base64 -d 2>/dev/null | od -An -v -tx1 | tr -d ' \n'
|
||||
elif have xxd; then
|
||||
printf '%s' "$1" | base64 -d 2>/dev/null | xxd -p | tr -d '\n'
|
||||
else
|
||||
printf '%s' "$1" | base64 -d 2>/dev/null | hexdump -v -e '/1 "%02x"'
|
||||
fi
|
||||
}
|
||||
|
||||
# 从 checksums.txt 中解析当前平台发布包的哈希(按平台标记匹配,排除 DEBUG)
|
||||
function ck_hash() {
|
||||
grep "SamWaf_${OS_ARCH} " "$1" 2>/dev/null | grep -vi debug | grep -i 'tar.gz' | head -1 | awk '{print $1}'
|
||||
}
|
||||
|
||||
# 从 latest.json 中解析当前平台压缩包的 sha256(文件名含 OS_ARCH 且非 DEBUG)
|
||||
function l_hash() {
|
||||
awk -v tok="$OS_ARCH" '
|
||||
/"name"[[:space:]]*:/ {
|
||||
if (index($0, tok) && $0 !~ /[Dd][Ee][Bb][Uu][Gg]/) hit=1; else hit=0
|
||||
}
|
||||
hit && /"sha256"[[:space:]]*:/ {
|
||||
line=$0
|
||||
sub(/.*"sha256"[[:space:]]*:[[:space:]]*"/, "", line)
|
||||
sub(/".*/, "", line)
|
||||
print line
|
||||
exit
|
||||
}
|
||||
' "$1"
|
||||
}
|
||||
|
||||
# 初始化架构相关变量
|
||||
function init_arch_exec() {
|
||||
if [[ "$ARCH" == "x86_64" ]]; then
|
||||
EXEC_NAME="SamWafLinux64"; PLAT_JSON="linux-amd64"; OS_ARCH="Linux_x86_64"
|
||||
elif [[ "$ARCH" == "aarch64" ]] || [[ "$ARCH" == "arm64" ]]; then
|
||||
EXEC_NAME="SamWafLinuxArm64"; PLAT_JSON="linux-arm64"; OS_ARCH="Linux_arm64"
|
||||
else
|
||||
log_err "❌ 不支持的架构: $ARCH"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 组装各源的下载 URL
|
||||
# official:/latest 清单可用时下载版本化 tar.gz(与 git 逐字节相同);
|
||||
# 否则回退到 samwaf_update 的裸二进制 gz。
|
||||
function src_download_url() {
|
||||
case "$1" in
|
||||
official)
|
||||
if [ "$LATEST_JSON_OK" = "1" ]; then
|
||||
echo "${OFFICIAL_BASE}/latest/SamWaf_${OS_ARCH}.${VERSION}.tar.gz"
|
||||
else
|
||||
echo "${OFFICIAL_BASE}/samwaf_update/${VERSION}/${PLAT_JSON}.gz"
|
||||
fi ;;
|
||||
github) echo "${GITHUB_BASE}/releases/download/${VERSION}/SamWaf_${OS_ARCH}.${VERSION}.tar.gz" ;;
|
||||
gitee) echo "${GITEE_BASE}/releases/download/${VERSION}/SamWaf_${OS_ARCH}.${VERSION}.tar.gz" ;;
|
||||
esac
|
||||
}
|
||||
# 源产物类型:official 视 /latest 可用性为 tar 或 gz;其余为 tar.gz
|
||||
function src_kind() {
|
||||
case "$1" in
|
||||
official) [ "$LATEST_JSON_OK" = "1" ] && echo tar || echo gz ;;
|
||||
*) echo tar ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# 拉取 /latest/latest.json:正式版稳定通道自描述清单(版本 + 压缩包 SHA256)
|
||||
function fetch_latest_manifest() {
|
||||
LATEST_JSON_OK=0; L_TAR_SHA=""
|
||||
local f="$WORKDIR/latest.json"
|
||||
DL "${OFFICIAL_BASE}/latest/latest.json" "$f" 2>/dev/null || return
|
||||
local ver hash
|
||||
ver=$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$f" | head -1)
|
||||
hash=$(l_hash "$f")
|
||||
[ -n "$ver" ] && VERSION="$ver"
|
||||
if [ ${#hash} -eq 64 ]; then
|
||||
L_TAR_SHA="$hash"; LATEST_JSON_OK=1
|
||||
log_ok "🔐 已获取官方 /latest 清单: ${VERSION} (tar sha256=${L_TAR_SHA:0:16}...)"
|
||||
fi
|
||||
}
|
||||
|
||||
# 拉取 samwaf_update 清单:填充 VERSION(若未定)与 MANIFEST_BIN_SHA(可执行文件锚点)
|
||||
function fetch_manifest() {
|
||||
local f="$WORKDIR/manifest.json"
|
||||
if DL "${OFFICIAL_BASE}/samwaf_update/${PLAT_JSON}.json" "$f" 2>/dev/null; then
|
||||
local ver b64
|
||||
ver=$(sed -n 's/.*"Version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$f" | head -1)
|
||||
b64=$(sed -n 's/.*"Sha256"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$f" | head -1)
|
||||
[ -z "$VERSION" ] && [ -n "$ver" ] && VERSION="$ver"
|
||||
if [ -n "$b64" ]; then
|
||||
local hex; hex=$(b64_to_hex "$b64")
|
||||
if [ ${#hex} -eq 64 ]; then MANIFEST_BIN_SHA="$hex"; fi
|
||||
fi
|
||||
fi
|
||||
if [ -n "$MANIFEST_BIN_SHA" ]; then
|
||||
log_ok "🔐 已获取官方清单锚点: ${VERSION} (sha256=${MANIFEST_BIN_SHA:0:16}...)"
|
||||
else
|
||||
log_warn "⚠️ 官方清单不可用,将依赖 GitHub/Gitee 校验和"
|
||||
fi
|
||||
}
|
||||
|
||||
# 官方清单不可用时,从 git 源发现最新版本号
|
||||
function discover_version_from_git() {
|
||||
local f="$WORKDIR/rel.json" tag=""
|
||||
if DL "https://gitee.com/api/v5/repos/samwaf/SamWaf/releases/latest" "$f" 2>/dev/null; then
|
||||
tag=$(sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$f" | head -1)
|
||||
fi
|
||||
if [ -z "$tag" ] && DL "https://api.github.com/repos/samwafgo/SamWaf/releases/latest" "$f" 2>/dev/null; then
|
||||
tag=$(sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$f" | head -1)
|
||||
fi
|
||||
[ -n "$tag" ] && VERSION="$tag"
|
||||
}
|
||||
|
||||
# 建立跨源一致性:汇总 官方latest / GitHub / Gitee 三者的压缩包 SHA256 并比对
|
||||
function establish_consensus() {
|
||||
CK_TAR_SHA=""; CONSENSUS_HOSTS=0; GH_CK_OK=0; GT_CK_OK=0
|
||||
local verNoV="${VERSION#v}"
|
||||
local gh="$WORKDIR/ck_gh.txt" gt="$WORKDIR/ck_gt.txt" hgh="" hgt=""
|
||||
DL "${GITHUB_BASE}/releases/download/${VERSION}/SamWaf_${verNoV}_checksums.txt" "$gh" 2>/dev/null && hgh=$(ck_hash "$gh")
|
||||
DL "${GITEE_BASE}/releases/download/${VERSION}/SamWaf_${verNoV}_checksums.txt" "$gt" 2>/dev/null && hgt=$(ck_hash "$gt")
|
||||
[ -n "$hgh" ] && GH_CK_OK=1
|
||||
[ -n "$hgt" ] && GT_CK_OK=1
|
||||
|
||||
# 汇总所有可用的压缩包哈希(官方 latest.json / GitHub / Gitee)
|
||||
local vals=() names=()
|
||||
[ -n "$L_TAR_SHA" ] && { vals+=("$L_TAR_SHA"); names+=("官方latest"); }
|
||||
[ -n "$hgh" ] && { vals+=("$hgh"); names+=("GitHub"); }
|
||||
[ -n "$hgt" ] && { vals+=("$hgt"); names+=("Gitee"); }
|
||||
|
||||
CONSENSUS_HOSTS=${#vals[@]}
|
||||
if [ "$CONSENSUS_HOSTS" -eq 0 ]; then
|
||||
log_warn "⚠️ 官方latest / GitHub / Gitee 压缩包校验和均不可用"
|
||||
return
|
||||
fi
|
||||
local base="${vals[0]}" i j
|
||||
for i in "${!vals[@]}"; do
|
||||
if [ "${vals[$i]}" != "$base" ]; then
|
||||
log_err "🚨 压缩包校验和跨源不一致,疑似源污染,已中止!"
|
||||
for j in "${!vals[@]}"; do log_err " ${names[$j]}: ${vals[$j]}"; done
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
CK_TAR_SHA="$base"
|
||||
if [ "$CONSENSUS_HOSTS" -ge 2 ]; then
|
||||
log_ok "🤝 跨源压缩包校验和一致(${CONSENSUS_HOSTS} 源:${names[*]}) (sha256=${base:0:16}...)"
|
||||
else
|
||||
log_warn "⚠️ 仅 ${names[0]} 提供压缩包校验和(单源)"
|
||||
fi
|
||||
}
|
||||
|
||||
# 校验准备:确定版本、锚点、一致性校验和,并执行安全策略闸门
|
||||
function prepare_verification() {
|
||||
fetch_latest_manifest # 官方 /latest 压缩包锚点(正式版稳定通道)
|
||||
fetch_manifest # 官方 samwaf_update 可执行文件锚点
|
||||
[ -z "$VERSION" ] && discover_version_from_git
|
||||
if [ -z "$VERSION" ]; then
|
||||
log_err "❌ 无法确定最新版本号(所有源均不可达)"
|
||||
exit 1
|
||||
fi
|
||||
log_info "📦 目标版本: ${VERSION}"
|
||||
|
||||
establish_consensus
|
||||
|
||||
# 相互独立的可信主机数(update.samwaf.com 的两个清单只算 1 个主机)
|
||||
local official_ok=0
|
||||
if [ -n "$L_TAR_SHA" ] || [ -n "$MANIFEST_BIN_SHA" ]; then official_ok=1; fi
|
||||
local distinct_hosts=$((official_ok + GH_CK_OK + GT_CK_OK))
|
||||
|
||||
if [ "$VERIFY_MODE" = "anchor" ]; then
|
||||
if [ -z "$MANIFEST_BIN_SHA" ] && [ -z "$L_TAR_SHA" ]; then
|
||||
log_err "❌ anchor 模式需要官方清单(/latest 或 samwaf_update),但均不可用。"
|
||||
log_err " 可改用 SAMWAF_VERIFY=consensus 或稍后重试。"
|
||||
exit 1
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
# consensus 模式(默认):至少两个相互独立的主机为发布物背书
|
||||
if [ -z "$CK_TAR_SHA" ] && [ -z "$MANIFEST_BIN_SHA" ]; then
|
||||
log_err "❌ 无任何可信校验基准(官方清单与 GitHub/Gitee 校验和均缺失),已中止。"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$distinct_hosts" -lt 2 ]; then
|
||||
log_err "❌ 仅 ${distinct_hosts} 个可信来源可达,无法建立跨源一致性,已中止。"
|
||||
log_err " 请确保能访问 update.samwaf.com 与 GitHub/Gitee 中的至少两个;"
|
||||
log_err " 或设置 SAMWAF_VERIFY=anchor(不推荐)后重试。"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 测速:probe <url> -> 输出首字节耗时(秒),不可达输出 999
|
||||
# 说明:以“首字节耗时(TTFB)+HTTP 状态码”判定可达性,忽略 curl 退出码——
|
||||
# 部分 CDN 不支持 Range,会整包返回并触发 --max-time,但只要拿到 TTFB
|
||||
# 即视为可达,避免把“可用但非秒开”的镜像误判为不可达。
|
||||
function probe() {
|
||||
local url="$1" out code sec
|
||||
have curl || { echo 500; return; }
|
||||
out=$(curl -o /dev/null -sL -k --connect-timeout 3 --max-time 8 -r 0-0 \
|
||||
-w '%{http_code} %{time_starttransfer}' "$url" 2>/dev/null)
|
||||
code=${out%% *}; sec=${out##* }
|
||||
if [[ "$code" =~ ^[23] ]] && [ -n "$sec" ] && [ "$sec" != "0.000000" ]; then
|
||||
echo "$sec"
|
||||
else
|
||||
echo 999
|
||||
fi
|
||||
}
|
||||
|
||||
# 依测速对候选源排序(快者在前);支持强制指定
|
||||
function order_sources() {
|
||||
local candidates=("$@")
|
||||
if [ -n "$FORCE_SOURCE" ]; then
|
||||
local ok=0 c
|
||||
for c in "${candidates[@]}"; do [ "$c" = "$FORCE_SOURCE" ] && ok=1; done
|
||||
if [ "$ok" = "1" ]; then
|
||||
log_info "📌 已按 SAMWAF_SOURCE 强制使用下载源: $FORCE_SOURCE" >&2
|
||||
echo "$FORCE_SOURCE"; return
|
||||
else
|
||||
log_warn "⚠️ 指定的源 [$FORCE_SOURCE] 当前不可用,回退为自动测速" >&2
|
||||
fi
|
||||
fi
|
||||
if ! have curl; then
|
||||
printf '%s\n' "${candidates[@]}" # 无 curl 无法测速,按默认顺序
|
||||
return
|
||||
fi
|
||||
log_info "⏱️ 正在测速各下载源..." >&2
|
||||
local s u t
|
||||
for s in "${candidates[@]}"; do
|
||||
u=$(src_download_url "$s")
|
||||
t=$(probe "$u")
|
||||
if [ "$t" = "999" ]; then
|
||||
log_warn " [$s] 不可达" >&2
|
||||
else
|
||||
printf ' [%-8s] 首字节 %ss\n' "$s" "$t" >&2
|
||||
fi
|
||||
echo "$t $s"
|
||||
done | sort -n | awk '{print $2}'
|
||||
}
|
||||
|
||||
# 依次尝试各源,下载并校验,成功后设置 VERIFIED_BIN
|
||||
function acquire_verified_binary() {
|
||||
local CANDIDATES
|
||||
if [ -n "$MANIFEST_BIN_SHA" ] || [ "$LATEST_JSON_OK" = "1" ]; then
|
||||
CANDIDATES=(official github gitee)
|
||||
else
|
||||
CANDIDATES=(github gitee)
|
||||
fi
|
||||
|
||||
local order; order=$(order_sources "${CANDIDATES[@]}")
|
||||
[ -z "$order" ] && { log_err "❌ 无可用下载源"; return 1; }
|
||||
|
||||
local s u kind tmp bin th bh
|
||||
for s in $order; do
|
||||
u=$(src_download_url "$s"); kind=$(src_kind "$s")
|
||||
log_info "⬇️ 尝试从 [$s] 下载: $u"
|
||||
tmp="$WORKDIR/dl_${s}"
|
||||
if ! DL "$u" "$tmp"; then log_warn " [$s] 下载失败,切换下一个源"; continue; fi
|
||||
|
||||
bin="$WORKDIR/bin_${s}"
|
||||
if [ "$kind" = "tar" ]; then
|
||||
if [ -n "$CK_TAR_SHA" ]; then
|
||||
th=$(sha256_of "$tmp")
|
||||
if [ "$th" != "$CK_TAR_SHA" ]; then
|
||||
log_warn " [$s] 压缩包校验和不匹配(过期/被篡改),跳过"; continue
|
||||
fi
|
||||
fi
|
||||
if ! tar xzf "$tmp" -C "$WORKDIR" "$EXEC_NAME" 2>/dev/null; then
|
||||
log_warn " [$s] 解压失败(未找到 $EXEC_NAME)"; continue
|
||||
fi
|
||||
mv -f "$WORKDIR/$EXEC_NAME" "$bin"
|
||||
else
|
||||
if ! gzip -dc "$tmp" > "$bin" 2>/dev/null; then
|
||||
log_warn " [$s] 解压失败"; continue
|
||||
fi
|
||||
fi
|
||||
|
||||
bh=$(sha256_of "$bin")
|
||||
if [ -n "$MANIFEST_BIN_SHA" ] && [ "$bh" != "$MANIFEST_BIN_SHA" ]; then
|
||||
log_warn " [$s] 可执行文件哈希与官方清单不符(过期/被篡改),跳过"; continue
|
||||
fi
|
||||
if [ -z "$MANIFEST_BIN_SHA" ] && [ -z "$CK_TAR_SHA" ]; then
|
||||
log_err " 无任何校验基准,拒绝安装"; return 1
|
||||
fi
|
||||
|
||||
VERIFIED_BIN="$bin"; USED_SOURCE="$s"; USED_BIN_SHA="$bh"
|
||||
log_ok "✅ [$s] 下载并校验通过 (sha256=${bh:0:16}...)"
|
||||
return 0
|
||||
done
|
||||
|
||||
log_err "❌ 所有下载源均失败或未通过校验"
|
||||
return 1
|
||||
}
|
||||
|
||||
# 部署已校验的可执行文件到安装目录并托管服务
|
||||
function deploy_binary() {
|
||||
mkdir -p "${setup_path}"
|
||||
install -m 0755 "$VERIFIED_BIN" "${setup_path}/${EXEC_NAME}"
|
||||
chown -R root:root "${setup_path}"
|
||||
( cd "${setup_path}" && ./"${EXEC_NAME}" install && ./"${EXEC_NAME}" start )
|
||||
}
|
||||
|
||||
# 检查是否已安装
|
||||
function check_installed() {
|
||||
if [ -f "${setup_path}/SamWafLinux64" ] || [ -f "${setup_path}/SamWafLinuxArm64" ]; then
|
||||
@@ -45,80 +436,53 @@ function check_installed() {
|
||||
|
||||
# 停止服务
|
||||
function stop_service() {
|
||||
if [ -f "${setup_path}/${exec_name}" ]; then
|
||||
echo -e "${BLUE}🛑 停止服务...${NC}"
|
||||
${setup_path}/${exec_name} stop
|
||||
if [ -f "${setup_path}/${EXEC_NAME}" ]; then
|
||||
log_info "🛑 停止服务..."
|
||||
"${setup_path}/${EXEC_NAME}" stop 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
# 卸载SamWaf
|
||||
function uninstall_samwaf() {
|
||||
echo -e "${BLUE}Uninstalling SamWaf...${NC}"
|
||||
log_info "Uninstalling SamWaf..."
|
||||
init_arch_exec
|
||||
stop_service
|
||||
${setup_path}/${exec_name} uninstall 2>/dev/null
|
||||
echo -e "${GREEN}✅ SamWaf uninstalled successfully${NC}"
|
||||
echo -e "${BLUE}📁 SamWaf files are still located at: ${setup_path}${NC}"
|
||||
echo -e "${RED}⚠️ 危险操作: 如果确认要删除,请自行手工执行以下命令(此操作不可恢复):${NC}"
|
||||
"${setup_path}/${EXEC_NAME}" uninstall 2>/dev/null
|
||||
log_ok "✅ SamWaf uninstalled successfully"
|
||||
log_info "📁 SamWaf files are still located at: ${setup_path}"
|
||||
log_err "⚠️ 危险操作: 如果确认要删除,请自行手工执行以下命令(此操作不可恢复):"
|
||||
echo -e " rm -rf \"${setup_path}\""
|
||||
exit 0
|
||||
}
|
||||
|
||||
# 安装SamWaf
|
||||
function install_samwaf() {
|
||||
echo -e "${BLUE}📥 Installing SamWaf...${NC}"
|
||||
echo -e "${BLUE}📁 Installation directory: ${setup_path}${NC}"
|
||||
log_info "📥 Installing SamWaf..."
|
||||
log_info "📁 Installation directory: ${setup_path}"
|
||||
check_deps
|
||||
init_arch_exec
|
||||
mkdir -p ${setup_path}
|
||||
temp_file="/tmp/samwaf.tar.gz"
|
||||
echo -e "${BLUE}📥 Downloading from ${url}...${NC}"
|
||||
wget --no-check-certificate -O "${temp_file}" "${url}" || {
|
||||
echo -e "${RED}❌ Download failed${NC}"
|
||||
exit 1
|
||||
}
|
||||
echo -e "${BLUE}📦 Extracting...${NC}"
|
||||
tar xzf "${temp_file}" -C ${setup_path} || {
|
||||
echo -e "${RED}❌ Extract failed${NC}"
|
||||
exit 1
|
||||
}
|
||||
# ✅ 统一所有权限为 root
|
||||
chown -R root:root "${setup_path}"
|
||||
chmod +x ${setup_path}/${exec_name}
|
||||
cd ${setup_path}
|
||||
./${exec_name} install
|
||||
./${exec_name} start
|
||||
rm -f "${temp_file}"
|
||||
WORKDIR=$(mktemp -d "${TMPDIR:-/tmp}/samwaf.XXXXXX")
|
||||
prepare_verification
|
||||
acquire_verified_binary || exit 1
|
||||
deploy_binary
|
||||
show_info
|
||||
}
|
||||
|
||||
# 更新SamWaf
|
||||
function update_samwaf() {
|
||||
echo -e "${BLUE}🔄 Updating SamWaf...${NC}"
|
||||
log_info "🔄 Updating SamWaf..."
|
||||
if ! check_installed; then
|
||||
echo -e "${RED}❌ 未检测到 SamWaf 安装,请先执行安装${NC}"
|
||||
log_err "❌ 未检测到 SamWaf 安装,请先执行安装"
|
||||
exit 1
|
||||
fi
|
||||
check_deps
|
||||
init_arch_exec
|
||||
WORKDIR=$(mktemp -d "${TMPDIR:-/tmp}/samwaf.XXXXXX")
|
||||
prepare_verification
|
||||
acquire_verified_binary || exit 1
|
||||
stop_service
|
||||
temp_file="/tmp/samwaf_update.tar.gz"
|
||||
echo -e "${BLUE}⬇️ 下载最新版本...${NC}"
|
||||
wget --no-check-certificate -O "${temp_file}" "${url}" || {
|
||||
echo -e "${RED}❌ 下载失败${NC}"
|
||||
exit 1
|
||||
}
|
||||
echo -e "${BLUE}📦 解压并替换...${NC}"
|
||||
tar xzf "${temp_file}" -C ${setup_path} || {
|
||||
echo -e "${RED}❌ 解压失败${NC}"
|
||||
exit 1
|
||||
}
|
||||
# ✅ 统一所有权限为 root
|
||||
chown -R root:root "${setup_path}"
|
||||
chmod +x ${setup_path}/${exec_name}
|
||||
cd ${setup_path}
|
||||
./${exec_name} install
|
||||
./${exec_name} start
|
||||
rm -f "${temp_file}"
|
||||
echo -e "${GREEN}✅ SamWaf 更新完成${NC}"
|
||||
deploy_binary
|
||||
log_ok "✅ SamWaf 更新完成(版本 ${VERSION},来源 ${USED_SOURCE})"
|
||||
}
|
||||
|
||||
# 显示信息
|
||||
@@ -126,10 +490,13 @@ function show_info() {
|
||||
ipv4_address=$(curl -4 -sS --connect-timeout 4 -m 5 http://myexternalip.com/raw 2>/dev/null)
|
||||
local_ip=$(ip addr | grep -E -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | grep -E -v "^127\.|^255\.|^0\." | head -n 1)
|
||||
|
||||
echo -e "${GREEN}✅ SamWaf installed successfully!${NC}"
|
||||
log_ok "✅ SamWaf installed successfully!"
|
||||
echo -e "=================================================================="
|
||||
echo -e "📋 SamWaf管理信息"
|
||||
echo -e "=================================================================="
|
||||
echo -e " 🏷️ 安装版本: ${VERSION}"
|
||||
echo -e " 🌐 下载来源: ${USED_SOURCE} 🔐 校验模式: ${VERIFY_MODE}"
|
||||
[ -n "$USED_BIN_SHA" ] && echo -e " 🧾 已校验哈希: ${USED_BIN_SHA}"
|
||||
[ "$ipv4_address" ] && echo -e " 🌐 外网管理地址: http://${ipv4_address}:26666"
|
||||
[ "$local_ip" ] && echo -e " 🏠 内网管理地址: http://${local_ip}:26666"
|
||||
echo -e " 👤 默认用户名: admin"
|
||||
@@ -138,32 +505,38 @@ function show_info() {
|
||||
echo -e " ⚠️ 首次登录后请立即修改密码"
|
||||
echo -e ""
|
||||
echo -e " 📁 安装目录: ${setup_path}"
|
||||
echo -e " 🔧 服务管理: cd ${setup_path} && ./${exec_name} [start|stop]"
|
||||
echo -e " 🗑️ 卸载命令: bash $(basename $0) uninstall"
|
||||
echo -e " 🔄 更新命令: bash $(basename $0) update"
|
||||
echo -e " 🔧 服务管理: cd ${setup_path} && ./${EXEC_NAME} [start|stop]"
|
||||
echo -e " 🗑️ 卸载命令: bash $(basename "$0") uninstall"
|
||||
echo -e " 🔄 更新命令: bash $(basename "$0") update"
|
||||
echo -e " 📣 欢迎关注 SamWaf 开源防火墙公众号,获取最新版本信息与技术教程"
|
||||
echo -e " 公众号名称:\033[0;32mSamWaf开源防火墙\033[0m"
|
||||
echo -e " 🔗 Gitee: https://gitee.com/samwaf/SamWaf"
|
||||
echo -e " 🔗 GitHub: https://github.com/samwafgo/SamWaf"
|
||||
echo -e " 公众号名称:${GREEN}SamWaf开源防火墙${NC}"
|
||||
echo -e " 🔗 Gitee: ${GITEE_BASE}"
|
||||
echo -e " 🔗 GitHub: ${GITHUB_BASE}"
|
||||
echo -e " 🔗 Atomgit: ${ATOMGIT_PAGE} (需登录下载)"
|
||||
echo -e "=================================================================="
|
||||
}
|
||||
|
||||
# 主程序
|
||||
# ------------------------------------------------------------------------ 主程序
|
||||
case "$1" in
|
||||
uninstall)
|
||||
uninstall_samwaf
|
||||
;;
|
||||
update)
|
||||
# 允许第二个参数覆盖下载源,例如: bash install_samwaf.sh update gitee
|
||||
[ -n "$2" ] && FORCE_SOURCE="$2"
|
||||
update_samwaf
|
||||
;;
|
||||
*)
|
||||
# 首参可为 install 或空;第二参数可覆盖下载源,例如: install gitee
|
||||
if [ "$1" = "install" ] && [ -n "$2" ]; then FORCE_SOURCE="$2"; fi
|
||||
if [ "$1" != "install" ] && [ -n "$1" ]; then FORCE_SOURCE="$1"; fi
|
||||
if check_installed; then
|
||||
echo -e "${GREEN}✅ SamWaf 已安装,无需重复安装${NC}"
|
||||
log_ok "✅ SamWaf 已安装,无需重复安装"
|
||||
echo -e "📁 安装目录: ${setup_path}"
|
||||
echo -e "如需更新请执行: bash $(basename $0) update"
|
||||
echo -e "如需卸载请执行: bash $(basename $0) uninstall"
|
||||
echo -e "如需更新请执行: bash $(basename "$0") update"
|
||||
echo -e "如需卸载请执行: bash $(basename "$0") uninstall"
|
||||
else
|
||||
install_samwaf
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
esac
|
||||
|
||||
Reference in New Issue
Block a user