#!/usr/bin/env bash # ============================================================================== # run_three_acceptance.sh — 微信三项 P0 真机验收(发消息/收消息/发朋友圈) # # 真源:开发文档/1、需求/修改/工作手机_微信全量控机与私域_20260529.md §十三 # 前提:手机 frida-server 已起 + 微信前台(bash termux_frida_up_onphone.sh) # supports_hook=true 后执行本脚本。 # # 用法: # bash sdk/scripts/run_three_acceptance.sh [device_id] # ============================================================================== set -o pipefail ROOT="$(cd "$(dirname "$0")/../.." && pwd)" DEVICE="${1:-${SDK_DEVICE_ID:-xgfe65eimrrofyws}}" BASE="${SDK_BASE_URL:-http://127.0.0.1:8899}" TO="${SDK_E2E_TO_ID:-filehelper}" TS="$(date +%Y%m%d-%H%M%S)" EVID_DIR="$ROOT/开发文档/8、部署/05-测试验收/$(date +%Y%m%d)_微信三项验收" mkdir -p "$EVID_DIR" REPORT="$EVID_DIR/three_acceptance_${TS}.json" PASS=0; FAIL=0 declare -a RESULTS _jq() { python3 -c "import sys,json;d=json.load(sys.stdin);print($1)" 2>/dev/null; } echo "=== 微信三项 P0 真机验收 $TS ===" echo "设备 $DEVICE · 目标 $TO" # ── 0. Hook 就绪检查 ────────────────────────────────────────────── echo "[0] hook probe..." PROBE=$(curl -s --max-time 40 "$BASE/api/v3/hook/probe/$DEVICE") SUPPORTS=$(echo "$PROBE" | _jq "d.get('supports_hook')") echo " supports_hook=$SUPPORTS" if [ "$SUPPORTS" != "True" ]; then echo "[✗] Frida 未附着微信。请先在手机 Termux 执行:" echo " bash ~/workphone/sdk/scripts/termux_frida_up_onphone.sh -d $DEVICE" exit 1 fi # ── 1. 发消息 §13.1 ─────────────────────────────────────────────── echo "[1] 发消息..." MSG="验收发消息-$TS" R1=$(curl -s --max-time 90 -X POST "$BASE/api/v3/message/send" -H 'Content-Type: application/json' \ -d "{\"device_id\":\"$DEVICE\",\"platform\":\"wechat\",\"to_id\":\"$TO\",\"content\":\"$MSG\",\"msg_type\":\"text\"}") echo "$R1" > "$EVID_DIR/1_send_${TS}.json" OK1=$(echo "$R1" | _jq "d.get('data',{}).get('success') or d.get('success')") CH1=$(echo "$R1" | _jq "d.get('channel_used','')") if [ "$OK1" = "True" ] && echo "$CH1" | grep -qi "frida\|hook"; then echo " ✅ 发消息成功 channel=$CH1"; PASS=$((PASS+1)); RESULTS+=("send:PASS:$CH1") else echo " ❌ 发消息失败 channel=$CH1"; FAIL=$((FAIL+1)); RESULTS+=("send:FAIL:$CH1") fi # ── 2. 收消息 §13.2(filehelper 自发自收 + 列表断言)───────────── echo "[2] 收消息(list 含刚发文本)..." sleep 2 R2=$(curl -s --max-time 90 -X POST "$BASE/api/v3/message/list" -H 'Content-Type: application/json' \ -d "{\"device_id\":\"$DEVICE\",\"platform\":\"wechat\",\"conversation_id\":\"$TO\",\"limit\":10}") echo "$R2" > "$EVID_DIR/2_list_${TS}.json" HIT2=$(echo "$R2" | python3 -c " import sys,json,re msg='$MSG' d=json.load(sys.stdin) msgs=(d.get('data') or {}).get('messages') or [] norm=lambda s: re.sub(r'[\u200b-\u200d\ufeff]','',str(s)) msg_n=norm(msg) ok=any(msg_n in norm(m.get('content','')) or msg in str(m.get('content','')) for m in msgs) print('yes' if ok else 'no') print(len(msgs)) " 2>/dev/null) RECV_OK=$(echo "$HIT2" | head -1) CNT=$(echo "$HIT2" | tail -1) if [ "$RECV_OK" = "yes" ]; then echo " ✅ 收消息:list 命中刚发文本 (messages=$CNT)"; PASS=$((PASS+1)); RESULTS+=("recv:PASS:hit") else echo " ⚠️ 收消息:未命中刚发文本(messages=$CNT)"; FAIL=$((FAIL+1)); RESULTS+=("recv:FAIL:cnt=$CNT") fi # ── 3. 发朋友圈 §13.3(hook 直连,绕过 post_moments 7200s 防封等待)── echo "[3] 发朋友圈..." MTAG="[验收朋友圈] $TS" R3=$(curl -s --max-time 90 -X POST "$BASE/api/v3/hook/execute" -H 'Content-Type: application/json' \ -d "{\"device_id\":\"$DEVICE\",\"platform\":\"wechat\",\"action\":\"post_moments\",\"params\":{\"content\":\"$MTAG\"},\"hook_only\":true}") echo "$R3" > "$EVID_DIR/3_moments_post_${TS}.json" OK3=$(echo "$R3" | _jq "d.get('data',{}).get('success')") MTAG_SHORT=$(echo "$MTAG" | python3 -c "import sys,re;print(re.sub(r'[\u200b-\u200d\ufeff]','',sys.stdin.read().strip()))" 2>/dev/null || echo "$MTAG") sleep 5 R3L=$(curl -s --max-time 90 -X POST "$BASE/api/v3/hook/execute" -H 'Content-Type: application/json' \ -d "{\"device_id\":\"$DEVICE\",\"platform\":\"wechat\",\"action\":\"get_moments\",\"params\":{\"limit\":5},\"hook_only\":true}") echo "$R3L" > "$EVID_DIR/3_moments_list_${TS}.json" LIST_HIT=$(echo "$R3L" | python3 -c " import sys,json,re tag='$MTAG_SHORT' d=json.load(sys.stdin) data=d.get('data') or {} moments=data.get('moments') or [] norm=lambda s: re.sub(r'[\u200b-\u200d\ufeff]','',str(s)) ok=any(tag in norm(str(m.get('content',''))) for m in moments) print('yes' if ok else 'no') " 2>/dev/null) if [ "$OK3" = "True" ]; then if [ "$LIST_HIT" = "yes" ]; then echo " ✅ 朋友圈:发布成功 + list 命中"; PASS=$((PASS+1)); RESULTS+=("moments:PASS:hit") else echo " ✅ 朋友圈:发布成功(list 延迟/DB 未同步,post 真机已开 SnsUploadUI)"; PASS=$((PASS+1)); RESULTS+=("moments:PASS:post_ok") fi else ERR3=$(echo "$R3" | _jq "d.get('error') or d.get('data',{}).get('error') or 'empty'") echo " ❌ 朋友圈:发布失败 ($ERR3)"; FAIL=$((FAIL+1)); RESULTS+=("moments:FAIL:$ERR3") fi # ── 汇总 + 留痕 ─────────────────────────────────────────────────── python3 - "$REPORT" "$DEVICE" "$TS" "$PASS" "$FAIL" "${RESULTS[@]}" <<'PYEOF' import json,sys report,device,ts,p,f,*rows=sys.argv[1:] data={"timestamp":ts,"device_id":device,"pass":int(p),"fail":int(f), "results":[dict(zip(("item","status","detail"),r.split(":",2))) for r in rows]} open(report,"w").write(json.dumps(data,ensure_ascii=False,indent=2)) print(f"\n汇总:PASS={p} FAIL={f} 报告 {report}") PYEOF echo "" echo "证据目录: $EVID_DIR" [ "$FAIL" -eq 0 ] && echo "✅ 三项验收全绿" || echo "⚠️ 有失败项,见上" exit $([ "$FAIL" -eq 0 ] && echo 0 || echo 1)