142 lines
4.1 KiB
Bash
Executable File
142 lines
4.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
BASE="${SDK_BASE_URL:-http://127.0.0.1:8899}"
|
|
DEVICE="${SDK_DEVICE_ID:-xgfe65eimrrofyws}"
|
|
WAIT_SECONDS="${SDK_ACCEPT_WAIT_SECONDS:-0}"
|
|
POLL_SECONDS="${SDK_ACCEPT_POLL_SECONDS:-5}"
|
|
OUT="${SDK_ACCEPT_OUT:-sdk/agent/logs/wechat_accept_friend_$(date +%Y%m%d_%H%M%S)}"
|
|
mkdir -p "$OUT"
|
|
|
|
query_requests() {
|
|
curl -sS --max-time 45 -X POST "$BASE/api/v3/hook/execute" \
|
|
-H 'Content-Type: application/json' \
|
|
-d "{\"device_id\":\"$DEVICE\",\"platform\":\"wechat\",\"action\":\"get_friend_requests\",\"params\":{\"limit\":50},\"hook_only\":true}" \
|
|
> "$OUT/get_friend_requests.json"
|
|
}
|
|
|
|
extract_request() {
|
|
python3 - "$OUT/get_friend_requests.json" "$OUT" <<'PY'
|
|
import json
|
|
import pathlib
|
|
import sys
|
|
|
|
body = json.loads(pathlib.Path(sys.argv[1]).read_text())
|
|
data = body.get("data") if isinstance(body.get("data"), dict) else body
|
|
requests = data.get("requests") or []
|
|
selected = next(
|
|
(
|
|
item for item in requests
|
|
if item.get("encrypt_username") and item.get("ticket")
|
|
),
|
|
None,
|
|
)
|
|
out = pathlib.Path(sys.argv[2])
|
|
if not selected:
|
|
for name in ("encrypt_username", "ticket", "from_id"):
|
|
(out / f"{name}.txt").write_text("", encoding="utf-8")
|
|
raise SystemExit(1)
|
|
for name in ("encrypt_username", "ticket", "from_id"):
|
|
(out / f"{name}.txt").write_text(str(selected.get(name, "")), encoding="utf-8")
|
|
(out / "selected_request.json").write_text(
|
|
json.dumps(selected, ensure_ascii=False, indent=2),
|
|
encoding="utf-8",
|
|
)
|
|
PY
|
|
}
|
|
|
|
deadline=$(( $(date +%s) + WAIT_SECONDS ))
|
|
while true; do
|
|
query_requests
|
|
if extract_request; then
|
|
break
|
|
fi
|
|
if (( $(date +%s) >= deadline )); then
|
|
python3 - "$OUT" "$WAIT_SECONDS" <<'PY'
|
|
import json
|
|
import pathlib
|
|
import sys
|
|
|
|
out = pathlib.Path(sys.argv[1])
|
|
receipt = {
|
|
"success": False,
|
|
"status": "no_pending_friend_request",
|
|
"error_code": "friend_request_not_found",
|
|
"error_message": "当前没有携带有效票据的待通过好友请求",
|
|
"retryable": True,
|
|
"retry_after_seconds": 5,
|
|
"feedback": {
|
|
"level": "error",
|
|
"title": "暂无待通过好友请求",
|
|
"message": "收到新的好友请求后再次执行本命令。",
|
|
"action": "retry",
|
|
},
|
|
"waited_seconds": int(sys.argv[2]),
|
|
}
|
|
(out / "summary.json").write_text(
|
|
json.dumps(receipt, ensure_ascii=False, indent=2),
|
|
encoding="utf-8",
|
|
)
|
|
print(json.dumps(receipt, ensure_ascii=False, indent=2))
|
|
PY
|
|
exit 0
|
|
fi
|
|
sleep "$POLL_SECONDS"
|
|
done
|
|
|
|
ENCRYPT_USERNAME="$(cat "$OUT/encrypt_username.txt")"
|
|
TICKET="$(cat "$OUT/ticket.txt")"
|
|
FROM_ID="$(cat "$OUT/from_id.txt")"
|
|
|
|
python3 - "$DEVICE" "$ENCRYPT_USERNAME" "$TICKET" > "$OUT/accept_body.json" <<'PY'
|
|
import json
|
|
import sys
|
|
print(json.dumps({
|
|
"device_id": sys.argv[1],
|
|
"platform": "wechat",
|
|
"user_id": "",
|
|
"encrypt_username": sys.argv[2],
|
|
"ticket": sys.argv[3],
|
|
}, ensure_ascii=False))
|
|
PY
|
|
|
|
curl -sS --max-time 90 -X POST "$BASE/api/v3/friend/accept" \
|
|
-H 'Content-Type: application/json' \
|
|
--data-binary "@$OUT/accept_body.json" \
|
|
> "$OUT/accept.json"
|
|
|
|
if [[ -n "$FROM_ID" ]]; then
|
|
curl -sS --max-time 45 --get "$BASE/api/v3/friend/info" \
|
|
--data-urlencode "device_id=$DEVICE" \
|
|
--data-urlencode "platform=wechat" \
|
|
--data-urlencode "user_id=$FROM_ID" \
|
|
> "$OUT/readback.json"
|
|
fi
|
|
|
|
python3 - "$OUT" <<'PY'
|
|
import json
|
|
import pathlib
|
|
import sys
|
|
|
|
out = pathlib.Path(sys.argv[1])
|
|
accept = json.loads((out / "accept.json").read_text())
|
|
data = accept.get("data") if isinstance(accept.get("data"), dict) else accept
|
|
success = bool(data.get("success", accept.get("success", False)))
|
|
readback = None
|
|
if (out / "readback.json").exists():
|
|
readback = json.loads((out / "readback.json").read_text())
|
|
receipt = {
|
|
"success": success,
|
|
"status": "request_accepted" if success else "accept_failed",
|
|
"channel_used": accept.get("channel_used") or data.get("_channel_used", ""),
|
|
"accept": accept,
|
|
"readback": readback,
|
|
"evidence_dir": str(out.resolve()),
|
|
}
|
|
(out / "summary.json").write_text(
|
|
json.dumps(receipt, ensure_ascii=False, indent=2),
|
|
encoding="utf-8",
|
|
)
|
|
print(json.dumps(receipt, ensure_ascii=False, indent=2))
|
|
PY
|