mirror of
https://wget.la/https://github.com/Wxw-Gu/WechatExplorer
synced 2026-08-17 03:27:00 +08:00
- 使用 Electron safeStorage 加密存储并自动初始化 API Token - 为 health 以外的接口增加 Bearer Token 鉴权 - 限制 CORS 仅允许可信本地 Origin - 增加鉴权、Token rotation、safeStorage 和手动验收测试
117 lines
4.6 KiB
Bash
Executable File
117 lines
4.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# WechatExplorer v2.1.9 Local HTTP API 手动验收脚本
|
|
# 仅用于 macOS Terminal;不会写入或输出真实 API Token。
|
|
|
|
set -u
|
|
|
|
API_BASE_URL="${API_BASE_URL:-http://127.0.0.1:6131}"
|
|
API_BASE_URL="${API_BASE_URL%/}"
|
|
TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/wechatexplorer-api-test.XXXXXX")"
|
|
trap 'rm -rf "$TMP_DIR"' EXIT
|
|
|
|
PASS_COUNT=0
|
|
FAIL_COUNT=0
|
|
SKIP_COUNT=0
|
|
|
|
pass() { PASS_COUNT=$((PASS_COUNT + 1)); printf 'PASS %s\n' "$1"; }
|
|
fail() { FAIL_COUNT=$((FAIL_COUNT + 1)); printf 'FAIL %s%s\n' "$1" "${2:+ ($2)}"; }
|
|
skip() { SKIP_COUNT=$((SKIP_COUNT + 1)); printf 'SKIP %s\n' "$1"; }
|
|
|
|
printf 'WechatExplorer Local HTTP API 手动测试\n'
|
|
printf 'API 地址: %s\n\n' "$API_BASE_URL"
|
|
read -r -s -p '请输入 API Token(不会显示): ' API_TOKEN
|
|
printf '\n'
|
|
if [[ -z "$API_TOKEN" ]]; then
|
|
printf 'Token 不能为空。\n'
|
|
exit 2
|
|
fi
|
|
|
|
request() {
|
|
local method="$1" path="$2" auth="$3" origin="$4" body="${5:-}"
|
|
local out="$TMP_DIR/body" headers="$TMP_DIR/headers" err="$TMP_DIR/error"
|
|
local -a args=(--silent --show-error --max-time 10 -X "$method" -D "$headers" -o "$out" -w '%{http_code}')
|
|
[[ "$auth" == 1 ]] && args+=(-H "Authorization: Bearer $API_TOKEN")
|
|
[[ "$auth" == invalid ]] && args+=(-H 'Authorization: Bearer invalid')
|
|
[[ "$auth" == malformed ]] && args+=(-H 'Authorization: abc')
|
|
[[ "$auth" == bearer-only ]] && args+=(-H 'Authorization: Bearer')
|
|
[[ -n "$origin" ]] && args+=(-H "Origin: $origin")
|
|
if [[ -n "$body" ]]; then args+=(-H 'Content-Type: application/json' --data "$body"); fi
|
|
: >"$out"
|
|
: >"$headers"
|
|
: >"$err"
|
|
local status
|
|
status="$(curl "${args[@]}" "$API_BASE_URL$path" 2>"$err")"
|
|
CURL_STATUS="$status"
|
|
CURL_BODY="$(<"$out")"
|
|
CURL_HEADERS="$(<"$headers")"
|
|
}
|
|
|
|
expect_status() {
|
|
local name="$1" expected="$2" actual="$3"
|
|
if [[ "$actual" == "$expected" ]]; then pass "$name ($actual)"; else fail "$name" "期望 ${expected},实际 ${actual:-000}"; fi
|
|
}
|
|
|
|
printf '%s\n' '--- 基础鉴权 ---'
|
|
request GET /api/v1/health 0 ''
|
|
expect_status 'health 无 Token' 200 "$CURL_STATUS"
|
|
|
|
request GET /api/v1/current_time 0 ''
|
|
expect_status '受保护 endpoint 无 Token' 401 "$CURL_STATUS"
|
|
|
|
request GET /api/v1/current_time invalid ''
|
|
expect_status '错误 Token' 401 "$CURL_STATUS"
|
|
|
|
request GET /api/v1/current_time 1 ''
|
|
expect_status '正确 Token' 200 "$CURL_STATUS"
|
|
|
|
request GET /api/v1/current_time malformed ''
|
|
expect_status 'Authorization: abc' 401 "$CURL_STATUS"
|
|
|
|
request GET /api/v1/current_time bearer-only ''
|
|
expect_status 'Authorization: Bearer' 401 "$CURL_STATUS"
|
|
|
|
printf '%s\n' '--- CORS ---'
|
|
request OPTIONS /api/v1/health 0 http://localhost
|
|
expect_status 'OPTIONS / CORS localhost' 204 "$CURL_STATUS"
|
|
if [[ "$CURL_HEADERS" == *'Access-Control-Allow-Origin: http://localhost'* && "$CURL_HEADERS" == *'Access-Control-Allow-Headers: Content-Type, Authorization'* ]]; then
|
|
pass 'localhost Origin 响应头'
|
|
else
|
|
fail 'localhost Origin 响应头'
|
|
fi
|
|
|
|
request OPTIONS /api/v1/health 0 http://evil.example.com
|
|
expect_status 'evil Origin 被拒绝' 403 "$CURL_STATUS"
|
|
|
|
request GET /api/v1/health 0 ''
|
|
if [[ "$CURL_STATUS" == 200 ]]; then pass '无 Origin 的 curl 请求'; else fail '无 Origin 的 curl 请求' "实际 ${CURL_STATUS:-000}"; fi
|
|
|
|
printf '%s\n' '--- API stop 后连接测试 ---'
|
|
RUN_STOP_CHECK="${RUN_STOP_CHECK:-0}"
|
|
if [[ -t 0 && "$RUN_STOP_CHECK" != 1 ]]; then
|
|
read -r -p '现在请在 API Center 停止 API;完成后输入 y 验证连接失败,其他键跳过: ' STOP_CONFIRM
|
|
[[ "$STOP_CONFIRM" == y || "$STOP_CONFIRM" == Y ]] && RUN_STOP_CHECK=1
|
|
fi
|
|
if [[ "$RUN_STOP_CHECK" == 1 ]]; then
|
|
request GET /api/v1/health 0 ''
|
|
if [[ "$CURL_STATUS" == 000 ]]; then
|
|
pass 'API 已停止后连接失败'
|
|
else
|
|
fail 'API stop 后连接失败' "仍收到 HTTP ${CURL_STATUS:-000}"
|
|
fi
|
|
else
|
|
skip '未执行 stop 验证;也可在停止 API 后使用 RUN_STOP_CHECK=1 重新运行'
|
|
fi
|
|
|
|
printf '\n%s\n' '--- 人工验证项目(脚本不会自动操作) ---'
|
|
printf '%s\n' '1. API Center 默认隐藏 Token,点击“显示 Token”后可见,再点击隐藏。'
|
|
printf '%s\n' '2. 点击“复制 Token”,粘贴到安全位置确认复制成功;终端不要回显 Token。'
|
|
printf '%s\n' '3. 点击“重新生成 Token”并确认二次确认提示。'
|
|
printf '%s\n' '4. rotation 后,用旧 Token 请求 /api/v1/current_time 应立即返回 401。'
|
|
printf '%s\n' '5. 重启 App 后 Token 应保持不变。'
|
|
printf '%s\n' '6. 将 apiEnabled=false 后,API 应不再监听(可重新运行本脚本的 stop 测试)。'
|
|
|
|
printf '\n结果:PASS=%d FAIL=%d SKIP=%d\n' "$PASS_COUNT" "$FAIL_COUNT" "$SKIP_COUNT"
|
|
if (( FAIL_COUNT > 0 )); then exit 1; fi
|
|
exit 0
|