#!/bin/bash # test-mac.sh — 本机(Mac)指纹验证脚本 # 用途:验证 Node.js TLS 指纹、H2 连通性 # 运行方式:bash test-mac.sh set -euo pipefail GREEN='\033[0;32m' RED='\033[0;31m' YELLOW='\033[1;33m' NC='\033[0m' ok() { echo -e "${GREEN}✅ $*${NC}"; } fail() { echo -e "${RED}❌ $*${NC}"; } info() { echo -e "${YELLOW}ℹ $*${NC}"; } echo "══════════════════════════════════════" echo " MAC 本地指纹验证" echo "══════════════════════════════════════" # ── 1. Node.js 版本 ──────────────────────────────────────── echo "" echo "【1】Node.js 版本" NODE_VER=$(node --version 2>/dev/null || echo "未安装") echo " 本机 Node: $NODE_VER" if [[ "$NODE_VER" == v22* ]]; then ok "Node.js v22.x — 与 Claude CLI 内置版本匹配" else fail "Node.js 版本不是 v22.x(当前: $NODE_VER),JA4 指纹可能不一致" info "安装 v22: nvm install 22 && nvm use 22" fi # ── 2. Node.js JA4 TLS 指纹 ──────────────────────────────── echo "" echo "【2】Node.js TLS JA4 指纹(服务器实际产生的指纹)" JA4=$(node -e " const https = require('https'); https.get('https://tls.peet.ws/api/all', res => { let d=''; res.on('data',c=>d+=c); res.on('end',()=>{ try { console.log(JSON.parse(d).tls.ja4); } catch(e){ console.log('parse_error'); } }); }).on('error', e => console.log('error:'+e.message)); " 2>/dev/null) echo " JA4: $JA4" if [[ "$JA4" == t13* ]]; then ok "TLS 1.3,看起来是合法的 Node.js 指纹" else fail "JA4 获取失败或格式异常: $JA4" fi # ── 3. H2 连接 api.anthropic.com ─────────────────────────── echo "" echo "【3】HTTP/2 连通性(Anthropic)" H2_RESULT=$(node -e " const http2 = require('http2'); const s = http2.connect('https://api.anthropic.com', {}, () => { console.log('ok:' + s.socket.alpnProtocol); s.close(); }); s.on('error', e => { console.log('err:'+e.message); process.exit(0); }); setTimeout(()=>{ console.log('timeout'); process.exit(0); }, 5000); " 2>/dev/null) if [[ "$H2_RESULT" == ok:h2 ]]; then ok "Anthropic H2 连接成功(alpnProtocol: h2)" else fail "H2 连接失败: $H2_RESULT" fi # ── 4. H2 连接 googleapis.com ────────────────────────────── echo "" echo "【4】HTTP/2 连通性(Google / Gemini)" H2G=$(node -e " const http2 = require('http2'); const s = http2.connect('https://generativelanguage.googleapis.com', {}, () => { console.log('ok:' + s.socket.alpnProtocol); s.close(); }); s.on('error', e => { console.log('err:'+e.message); process.exit(0); }); setTimeout(()=>{ console.log('timeout'); process.exit(0); }, 5000); " 2>/dev/null) if [[ "$H2G" == ok:h2 ]]; then ok "Google API H2 连接成功" else fail "Google API H2 连接失败: $H2G" fi # ── 5. 本地 proxy 健康检查(如果本地起了) ───────────────── echo "" echo "【5】本地 node-tls-proxy 健康(端口 3456)" PROXY_PORT="${PROXY_PORT:-3456}" if curl -sf "http://127.0.0.1:${PROXY_PORT}/__health" -o /tmp/proxy_health.json 2>/dev/null; then SESSIONS=$(python3 -c "import json,sys; d=json.load(open('/tmp/proxy_health.json')); print(d.get('sessions',0))" 2>/dev/null || echo "?") H2HOSTS=$(python3 -c "import json,sys; d=json.load(open('/tmp/proxy_health.json')); print(','.join(d.get('h2Hosts',[])))" 2>/dev/null || echo "?") ok "Proxy 运行中 | sessions=$SESSIONS | h2Hosts=$H2HOSTS" else info "本地未运行 node-tls-proxy(端口 $PROXY_PORT),跳过" fi # ── 6. Jitter 延迟分布(如果 proxy 运行中)──────────────── echo "" echo "【6】Jitter 延迟测试(5次请求,通过本地 proxy)" if curl -sf "http://127.0.0.1:${PROXY_PORT:-3456}/__health" -o /dev/null 2>/dev/null; then for i in {1..5}; do START=$(date +%s%3N) curl -sf -X POST "http://127.0.0.1:${PROXY_PORT:-3456}/v1/messages" \ -H "x-forwarded-host: api.anthropic.com" \ -H "content-type: application/json" \ -d '{"model":"claude-opus-4-5","max_tokens":1}' -o /dev/null 2>/dev/null || true ELAPSED=$(($(date +%s%3N) - START)) echo " 请求 $i: ${ELAPSED}ms" done ok "延迟应在 80-1200ms 之间,非均匀分布" else info "本地未运行 proxy,跳过 Jitter 测试" fi echo "" echo "══════════════════════════════════════" echo " Mac 验证完成" echo " 关键指纹: $JA4" echo "══════════════════════════════════════"