Files
pangolin/app/kernel/fetch-desktop-bin.sh
T
wangjia 86157dfc99 fix(kernel): fetch 脚本改内置 SHA pin(sing-box 停发 checksums.txt)+修正 wintun SHA
- sing-box v1.13 起 Release 不再发布 checksums.txt,原脚本下载它 404,桌面内核
  拉取全平台失效。改为脚本内置各压缩包 SHA256(case 表,版本不符即报错)。
- WINTUN_SHA256 原值(90a6c2..)错误,更正为 wintun-0.14.1.zip 官方哈希(07c256..)。
- 已在 macOS 验证 windows/amd64 全流程:sing-box.exe + wintun.dll 下载+校验+解压通过。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 07:58:03 +08:00

237 lines
10 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# fetch-desktop-bin.sh — 从 sing-box GitHub Release 下载桌面平台二进制
#
# 用法: ./fetch-desktop-bin.sh <os> <arch> [--force]
# os : linux | darwin | windows
# arch : amd64 | arm64
# --force 忽略已有产物,强制重新下载
#
# 产物目录: dist/desktop/<os>-<arch>/
# Linux/macOS : sing-box
# Windows : sing-box.exe + wintun.dll
#
# SHA256 校验: 从官方 Release 下载 checksums.txt 后逐项验证。
# 校验通过后,checksums.txt 缓存于产物目录,可离线复核。
#
# Wintun (Windows 专用):
# 版本由 VERSION 中 WINTUN_VERSION 控制。
# 从 https://www.wintun.net/builds/wintun-<ver>.zip 下载,
# 校验 zip 的 SHA256(见下方 WINTUN_SHA256 变量),
# 提取对应 arch 的 wintun.dll 到产物目录。
#
# 幂等: 产物已存在且 SHA256 校验通过则跳过下载(传 --force 强制重下)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# ── 加载版本锚点 ─────────────────────────────────────────────────────────────
# shellcheck source=VERSION
. "${SCRIPT_DIR}/VERSION"
# ── Wintun ZIP SHA256(对应 WINTUN_VERSION=0.14.1)─────────────────────────
# 更新 WINTUN_VERSION 时须同步更新此值:
# curl -sL https://www.wintun.net/builds/wintun-<ver>.zip | sha256sum
WINTUN_SHA256="07c256185d6ee3652e09fa55c0b673e2624b565e02c4b9091c79ca7d2f24ef51"
# ── 参数解析 ─────────────────────────────────────────────────────────────────
if [[ $# -lt 2 ]]; then
printf 'Usage: %s <os> <arch> [--force]\n' "$0" >&2
printf ' os : linux | darwin | windows\n' >&2
printf ' arch: amd64 | arm64\n' >&2
exit 1
fi
TARGET_OS="$1"
TARGET_ARCH="$2"
FORCE=false
shift 2
for arg in "$@"; do
case "${arg}" in
--force) FORCE=true ;;
*) printf 'Unknown argument: %s\n' "${arg}" >&2; exit 1 ;;
esac
done
# ── 参数验证 ─────────────────────────────────────────────────────────────────
case "${TARGET_OS}" in
linux|darwin|windows) ;;
*) printf '✗ 不支持的 OS: %s(支持: linux | darwin | windows\n' "${TARGET_OS}" >&2; exit 1 ;;
esac
case "${TARGET_ARCH}" in
amd64|arm64) ;;
*) printf '✗ 不支持的 arch: %s(支持: amd64 | arm64\n' "${TARGET_ARCH}" >&2; exit 1 ;;
esac
# ── 路径与文件名配置 ─────────────────────────────────────────────────────────
DIST_DIR="${SCRIPT_DIR}/dist/desktop/${TARGET_OS}-${TARGET_ARCH}"
CACHE_DIR="${SCRIPT_DIR}/.build/cache"
VERSION_BARE="${SINGBOX_VERSION#v}" # 去掉前缀 v(如 v1.13.12 → 1.13.12
if [[ "${TARGET_OS}" == "windows" ]]; then
ARCHIVE_EXT="zip"
BIN_NAME="sing-box.exe"
else
ARCHIVE_EXT="tar.gz"
BIN_NAME="sing-box"
fi
ARCHIVE_STEM="sing-box-${VERSION_BARE}-${TARGET_OS}-${TARGET_ARCH}"
ARCHIVE_FILE="${ARCHIVE_STEM}.${ARCHIVE_EXT}"
GITHUB_BASE="https://github.com/SagerNet/sing-box/releases/download/${SINGBOX_VERSION}"
ARCHIVE_URL="${GITHUB_BASE}/${ARCHIVE_FILE}"
# ── sing-box 压缩包 SHA256(内置 pin)──────────────────────────────────────────
# sing-box 自 v1.13 起的 Release 不再发布 checksums.txt,故改为脚本内置各压缩包
# 的 SHA256。更新 SINGBOX_VERSION 时必须同步更新下表(case 键含版本号,未更新会
# 命中 *) 分支并报错,以防用错版本的哈希):
# curl -fsSL "${GITHUB_BASE}/<archive>" | shasum -a 256
EXPECTED_HASH=""
case "${ARCHIVE_FILE}" in
sing-box-1.13.12-windows-amd64.zip) EXPECTED_HASH="e93fc531134eb1beb4efa3c74990a24e48456098a31c03b60d5ddf17f223cf98" ;;
sing-box-1.13.12-darwin-arm64.tar.gz) EXPECTED_HASH="43eef86f0ea4a79c3696974f397a963c46a457ee46d1ffac9aa913944a5fc986" ;;
sing-box-1.13.12-darwin-amd64.tar.gz) EXPECTED_HASH="f3275316451bf1983bc059599c69c8ed0232d53a619d15cfd535f95cc9a4477a" ;;
sing-box-1.13.12-linux-amd64.tar.gz) EXPECTED_HASH="1540533adb3df24f5ad5f14b5c7ca3dbc2401b10a1c1eb278fcadcada47ec6c4" ;;
esac
OUT_BIN="${DIST_DIR}/${BIN_NAME}"
# ── 工具检查 ─────────────────────────────────────────────────────────────────
_need() {
if ! command -v "$1" >/dev/null 2>&1; then
printf '✗ 依赖未找到: %s\n' "$1" >&2; exit 1
fi
}
_need curl
_need sha256sum || _need shasum # macOS 用 shasumLinux 用 sha256sum
# 兼容 macOS (shasum -a 256) 和 Linux (sha256sum)
_sha256() {
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$1" | awk '{print $1}'
else
shasum -a 256 "$1" | awk '{print $1}'
fi
}
# ── 幂等检查(已有产物则跳过;--force 强制重下)────────────────────────────────
if [[ "${FORCE}" == false && -f "${OUT_BIN}" ]]; then
printf '✓ %s 已存在,跳过下载\n' "${OUT_BIN}"
printf ' 当前 SHA256: %s\n' "$(_sha256 "${OUT_BIN}")"
printf ' (传 --force 强制重新下载并校验压缩包)\n'
exit 0
fi
# ── 创建目录 ─────────────────────────────────────────────────────────────────
mkdir -p "${DIST_DIR}"
mkdir -p "${CACHE_DIR}"
ARCHIVE_CACHE="${CACHE_DIR}/${ARCHIVE_FILE}"
# 未在内置 pin 表中找到该压缩包的 SHA256(多半是 SINGBOX_VERSION 升级后没同步哈希)
if [[ -z "${EXPECTED_HASH}" ]]; then
printf '✗ 脚本内未内置 %s 的 SHA256\n' "${ARCHIVE_FILE}" >&2
printf ' 升级 SINGBOX_VERSION 后需在本脚本 case 表补该压缩包哈希:\n' >&2
printf ' curl -fsSL "%s" | shasum -a 256\n' "${ARCHIVE_URL}" >&2
exit 1
fi
# ── 下载二进制压缩包 ──────────────────────────────────────────────────────────
printf '==> 下载 %s…\n' "${ARCHIVE_FILE}"
curl -fSL --retry 3 --retry-delay 2 \
-o "${ARCHIVE_CACHE}" \
"${ARCHIVE_URL}"
# ── SHA256 校验(对压缩包,比对内置 pin)──────────────────────────────────────
printf '==> 校验 SHA256…\n'
ACTUAL_HASH="$(_sha256 "${ARCHIVE_CACHE}")"
if [[ "${ACTUAL_HASH}" != "${EXPECTED_HASH}" ]]; then
printf '✗ SHA256 不匹配!\n' >&2
printf ' 期望: %s\n' "${EXPECTED_HASH}" >&2
printf ' 实际: %s\n' "${ACTUAL_HASH}" >&2
rm -f "${ARCHIVE_CACHE}"
exit 1
fi
printf ' ✓ SHA256 匹配: %s\n' "${ACTUAL_HASH}"
# ── 解压二进制 ────────────────────────────────────────────────────────────────
printf '==> 解压 → %s\n' "${DIST_DIR}"
EXTRACT_TMP="${CACHE_DIR}/extract-${ARCHIVE_STEM}"
rm -rf "${EXTRACT_TMP}"
mkdir -p "${EXTRACT_TMP}"
if [[ "${ARCHIVE_EXT}" == "zip" ]]; then
if ! command -v unzip >/dev/null 2>&1; then
printf '✗ unzip 未找到\n' >&2; exit 1
fi
unzip -q "${ARCHIVE_CACHE}" -d "${EXTRACT_TMP}"
else
tar -xzf "${ARCHIVE_CACHE}" -C "${EXTRACT_TMP}"
fi
# sing-box 压缩包内层目录名与 ARCHIVE_STEM 相同
INNER_DIR="${EXTRACT_TMP}/${ARCHIVE_STEM}"
if [[ ! -f "${INNER_DIR}/${BIN_NAME}" ]]; then
printf '✗ 压缩包中未找到 %s/%s\n' "${ARCHIVE_STEM}" "${BIN_NAME}" >&2
exit 1
fi
cp "${INNER_DIR}/${BIN_NAME}" "${OUT_BIN}"
chmod 755 "${OUT_BIN}"
printf '\n✓ sing-box 二进制: %s\n' "${OUT_BIN}"
printf ' 版本验证: %s version\n' "${OUT_BIN}"
# ── Windows 额外处理: wintun.dll ─────────────────────────────────────────────
if [[ "${TARGET_OS}" == "windows" ]]; then
printf '\n==> Windows: 下载 wintun.dll (v%s)…\n' "${WINTUN_VERSION}"
WINTUN_ZIP_NAME="wintun-${WINTUN_VERSION}.zip"
WINTUN_URL="https://www.wintun.net/builds/${WINTUN_ZIP_NAME}"
WINTUN_ZIP_CACHE="${CACHE_DIR}/${WINTUN_ZIP_NAME}"
WINTUN_OUT="${DIST_DIR}/wintun.dll"
if [[ "${FORCE}" == false && -f "${WINTUN_OUT}" ]]; then
printf '✓ wintun.dll 已存在,跳过(传 --force 重新下载)\n'
else
curl -fSL --retry 3 --retry-delay 2 \
-o "${WINTUN_ZIP_CACHE}" \
"${WINTUN_URL}"
printf '==> 校验 wintun.zip SHA256…\n'
WINTUN_ACTUAL="$(_sha256 "${WINTUN_ZIP_CACHE}")"
if [[ "${WINTUN_ACTUAL}" != "${WINTUN_SHA256}" ]]; then
printf '✗ wintun.zip SHA256 不匹配!\n' >&2
printf ' 期望: %s\n' "${WINTUN_SHA256}" >&2
printf ' 实际: %s\n' "${WINTUN_ACTUAL}" >&2
printf ' 如果 WINTUN_VERSION 已更新,请同步更新脚本中的 WINTUN_SHA256\n' >&2
rm -f "${WINTUN_ZIP_CACHE}"
exit 1
fi
printf ' ✓ wintun.zip SHA256 匹配\n'
# 提取对应 arch 的 wintun.dll
# wintun zip 内路径: wintun/bin/<arch>/wintun.dll
WINTUN_EXTRACT="${CACHE_DIR}/extract-wintun"
rm -rf "${WINTUN_EXTRACT}"
mkdir -p "${WINTUN_EXTRACT}"
unzip -q "${WINTUN_ZIP_CACHE}" -d "${WINTUN_EXTRACT}"
WINTUN_DLL_SRC="${WINTUN_EXTRACT}/wintun/bin/${TARGET_ARCH}/wintun.dll"
if [[ ! -f "${WINTUN_DLL_SRC}" ]]; then
printf '✗ wintun zip 中未找到 %s arch 的 wintun.dll\n' "${TARGET_ARCH}" >&2
exit 1
fi
cp "${WINTUN_DLL_SRC}" "${WINTUN_OUT}"
printf '✓ wintun.dll: %s\n' "${WINTUN_OUT}"
fi
fi
# ── 最终输出摘要 ─────────────────────────────────────────────────────────────
printf '\n=== 产物清单: %s ===\n' "${DIST_DIR}"
ls -lh "${DIST_DIR}/"