Files
pangolin/app/kernel/poc/gen-poc-config.sh
T
wangjia 3c6a8a517a feat: 桌面端 PoC M1 — sing-box 子进程 TUN 接线 [tsk_SLCsjNgtmng3]
实现桌面端(macOS PoC)内核子进程管理,打通 sing-box TUN 模式全链路:

### client/lib/bridge/kernel_process.dart(完整实现,替换原有 stub)
- ClashApiClient: HTTP 客户端,支持 /connections / /proxies / /traffic(SSE) / /traffic(plain)
  - Bearer Token 鉴权;getConnections 用于就绪探测与流量统计;getTraffic SSE 读首帧后断开
- KernelProcess 接口: 新增 statusStream / statsStream 至接口定义
- DesktopKernelProcess:
  - spawn(configPath): 解析 Clash API 端口/secret → sudo sing-box run(macOS PoC)→
    轮询 /connections 等待就绪(20s 超时)→ emit connecting→on
  - kill(): SIGTERM + 等待 gracePeriod(5s) → SIGKILL → emit off
  - 意外退出: emit error(UI 可一键重连,不崩溃)
  - 统计轮询: 每秒 GET /connections,差分算 uploadSpeed/downloadSpeed
  - 二进制解析: ENV > exe同目录 > macOS Bundle Resources > 开发目录 > /usr/local/bin
- 辅助函数: generateClashApiPort(高位随机)、generateClashApiSecret(32B hex)

### client/lib/bridge/desktop_vpn_bridge.dart(新文件)
- DesktopVpnBridge implements VpnBridge:
  - start(configJson): injectClashApi(注入随机端口+secret)→ writeConfig(0600)→ kernel.spawn
  - stop(): kernel.kill(5s)
  - statusStream / statsStream: 代理 KernelProcess 事件流
  - selectOutbound: Clash API PUT /proxies/{group}
  - getActiveOutbound: 从 /proxies 读 now 字段
  - configDirOverride: 测试注入支持
  - injectClashApi: 静态方法,尊重已有 clash_api 配置,合并保留 experimental 其他字段

### client/test/bridge/kernel_process_test.dart(新文件)
- ClashApiClient 完整测试: headers / 解析 / PUT body / DELETE / 非 200 抛 HttpException
- generateClashApiPort / generateClashApiSecret 生成范围和格式测试
- DesktopVpnBridge.injectClashApi: 注入 / 尊重已有 / 保留字段 / 保留其他 experimental / 非法 JSON
- DesktopVpnBridge + FakeKernelProcess 集成: connecting→on / stop→off / statsStream / 意外退出 / spawn失败

### app/kernel/poc/(新目录)
- reality_client.config.json.tmpl: VLESS+REALITY+TUN 客户端配置模板
  - TUN inbound: auto_route + strict_route(macOS kill-switch 基础保护)
  - DNS: 防泄露(remote via VPN + cn 直连)
  - experimental.clash_api: 随机端口 + secret 占位符
- gen-poc-config.sh: 渲染模板为可用 JSON(从环境变量读 REALITY 参数)
- README.md: 完整 PoC 接线与 M1 验收步骤

提权说明(macOS PoC):
  · sudo 提权(开发机需配 /etc/sudoers.d/pangolin-singbox 或有 sudo 缓存)
  · 正式版: SMJobBless Helper + 公证(BACKLOG-11D-HELPER)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 17:53:50 +08:00

82 lines
3.0 KiB
Bash
Raw 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
# gen-poc-config.sh — 渲染 REALITY 客户端 PoC 配置(tsk_SLCsjNgtmng3
#
# 用法: ./gen-poc-config.sh [--out <output.json>]
#
# 从环境变量读取参数(须全部提供,无 --干跑 模式):
# SERVER_HOST EC2 IP(如 18.136.60.128
# SERVER_PORT Xray VLESS 监听端口(如 11443
# REALITY_UUID 客户端 UUID
# REALITY_PUBLIC_KEY REALITY 公钥
# REALITY_SHORT_ID REALITY shortId
# REALITY_SNI TLS SNI(如 www.apple.com
#
# 可选:
# CLASH_API_PORT Clash API 端口(默认随机 49152-65535
# CLASH_API_SECRET Clash API secret(默认随机 32 字节 hex
#
# 产物默认写到 /tmp/pangolin-poc-config.json(权限 0600)。
#
# 注意:REALITY 私钥等参数绝不入库,仅在运行时从 EC2 secrets/ 或 Bitwarden 取。
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TMPL="${SCRIPT_DIR}/reality_client.config.json.tmpl"
OUT="${1:---out}"
if [[ "${OUT}" == "--out" ]]; then
OUT="${2:-/tmp/pangolin-poc-config.json}"
shift 2 2>/dev/null || true
fi
# ── 参数检查 ──────────────────────────────────────────────────────
_require() {
local name="$1"
if [[ -z "${!name:-}" ]]; then
printf '✗ 环境变量 %s 未设置\n' "$name" >&2
printf ' 示例: export %s=<value>\n' "$name" >&2
exit 1
fi
}
_require SERVER_HOST
_require SERVER_PORT
_require REALITY_UUID
_require REALITY_PUBLIC_KEY
_require REALITY_SHORT_ID
REALITY_SNI="${REALITY_SNI:-www.apple.com}"
# 生成随机 Clash API 端口和 secret(若未指定)
if [[ -z "${CLASH_API_PORT:-}" ]]; then
CLASH_API_PORT="$(python3 -c 'import random; print(random.randint(49152,65535))')"
fi
if [[ -z "${CLASH_API_SECRET:-}" ]]; then
CLASH_API_SECRET="$(python3 -c 'import secrets; print(secrets.token_hex(32))')"
fi
# ── 渲染模板 ──────────────────────────────────────────────────────
printf '==> 渲染配置 → %s\n' "$OUT"
sed \
-e "s|__SERVER_HOST__|${SERVER_HOST}|g" \
-e "s|__SERVER_PORT__|${SERVER_PORT}|g" \
-e "s|__UUID__|${REALITY_UUID}|g" \
-e "s|__REALITY_PUBLIC_KEY__|${REALITY_PUBLIC_KEY}|g" \
-e "s|__REALITY_SHORT_ID__|${REALITY_SHORT_ID}|g" \
-e "s|__REALITY_SNI__|${REALITY_SNI}|g" \
-e "s|__CLASH_API_PORT__|${CLASH_API_PORT}|g" \
-e "s|__CLASH_API_SECRET__|${CLASH_API_SECRET}|g" \
"${TMPL}" > "${OUT}"
chmod 600 "${OUT}"
printf '✓ 已写入: %s\n' "$OUT"
printf ' Clash API: http://127.0.0.1:%s (secret len=%d)\n' \
"$CLASH_API_PORT" "${#CLASH_API_SECRET}"
printf ' Server: %s:%s\n' "$SERVER_HOST" "$SERVER_PORT"
printf '\n提示: 使用此配置测试前,请确认 sing-box 有 TUN 权限:\n'
printf ' sudo sh -c "echo \"%%(whoami)s ALL=(root) NOPASSWD: /path/to/sing-box\" >> /etc/sudoers.d/pangolin"\n'