127 lines
6.2 KiB
Bash
Executable File
127 lines
6.2 KiB
Bash
Executable File
#!/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)
|