HiroAlleyCat/wdgwars-api-tester

GitHub: HiroAlleyCat/wdgwars-api-tester

wdgwars-api-tester是一款用于HTTP API表面系统探测的工具。

Stars: 0 | Forks: 0

# wdgwars-api-tester **[WDGoWars](https://wdgwars.pl/)** HTTP API 表面的系统探测。 于 2026-05-29 在大规模 `/api/*` 404 崩溃期间构建。此工具的目的是 通过一条命令回答那天需要用 hourcurl 一个小时才能解决的问题: - 哪些端点是活跃的,与返回的样式 404 页面相比? - 未认证的 `/api/me` 返回 401(预期的行为)还是 404(路由未绑定)? - `/api/stats` 是否暴露了 LiteSpeed 管理遥测泄露? - 自上次快照以来有什么变化? 仅使用标准库的 Python 3。无需 `pip install`。单个文件。 ## 家族 WDGoWars 饲料家族中的兄弟仓库: - [Muninn](https://github.com/HiroAlleyCat/adsb-to-wdgwars) — ADS-B 饲料 - [Heimdall](https://github.com/HiroAlleyCat/meshcore-to-wdgwars) — MeshCore LoRa 饲料 - [wigle-to-wdgwars](https://github.com/HiroAlleyCat/wigle-to-wdgwars) — WiGLE Wi-Fi/BLE 饲料 - [gungnir](https://github.com/HiroAlleyCat/gungnir) — 共享 HMAC 传输库 ## 快速开始 ``` # 使用所有三种身份验证变体(无、垃圾、有效)探测 apex python3 wdgwars_api_tester.py # 添加 www. 和 api. 子域名 python3 wdgwars_api_tester.py --hosts all # 探测自定义主机(预发布、分支、本地模拟)——任何以 # http:// 或 https:// 开头的都成为目标,而不是 wdgwars.pl。 python3 wdgwars_api_tester.py --hosts http://127.0.0.1:9999 --variants none # 机器可读 python3 wdgwars_api_tester.py --json > snapshot.json # 仅输出总体结论词 + 退出代码(适用于 shell / CI) python3 wdgwars_api_tester.py --quiet --variants none,garbage # → 打印 `HEALTHY` / `DEGRADED` / `OUTAGE` / `UNREACHABLE` # 以及可选的 `+LEAK` 或 `+SENTINEL-DIVERGED` 后缀。 # 每 60 秒轮询一次,在状态变化时打印紧凑的增量。 # 在恢复时刻(首次进入 HEALTHY)打印完整表格。 python3 wdgwars_api_tester.py --watch 60 # 快照一次,然后与未来的运行进行比较 python3 wdgwars_api_tester.py --baseline baseline.json # 在状态变化时监视 + Telegram 自页(无需桥接) export TELEGRAM_BOT_TOKEN=123456:ABC... export TELEGRAM_CHAT_ID=-1001234567890 python3 wdgwars_api_tester.py --watch 60 --alert-telegram # 在状态变化时监视 + Discord / Slack / n8n / PagerDuty(任何 webhook URL) python3 wdgwars_api_tester.py --watch 60 \ --alert-webhook https://discord.com/api/webhooks/.../... # 在状态变化时监视 + 任意 shell 命令 python3 wdgwars_api_tester.py --watch 60 \ --exec-on-change 'echo "$WDGWARS_PREV_OVERALL → $WDGWARS_OVERALL" | mail -s "wdgwars alert" me@example.com' ``` ## API 密钥 与 [wigle-to-wdgwars](https://github.com/HiroAlleyCat/wigle-to-wdgwars) 具有相同的优先级: 1. `--key` CLI 标志 2. `$WDGWARS_API_KEY` 3. `~/.config/wigle-to-wdgwars/wdgwars.key` 如果没有找到密钥,则自动删除 `valid` 变体,并且只运行 `none` 和 `garbage` 变体。 ## 它探测的内容 | 探测 | 方法 | 路径 | 认证 | 备注 | |---|---|---|---|---| | `api-root` | GET | `/api/` | 无 | /api/ 子树的基线形状。 | | `me` | GET | `/api/me` | 是 | 身份。未认证 → 401,不是 404。 | | `upload-history` | GET | `/api/upload-history?limit=5` | 是 | 2026-04-27 添加。 | | `upload-csv` | POST | `/api/upload-csv` | 是 | WiGLE-1.6 多部分,混合类型。 | | `v2-upload-csv` | POST + GET | `/api/v2/upload-csv` → `/api/v2/upload-job/` | 是 | 异步管道:POST 202 → 轮询直到 `done`/`failed`(6 次轮询,每次 1 秒)。捕获独立于 v1 的 v2-parser 回退。 | | `signed-upload` | GET | `/api/upload/` | 是 | HMAC JSON 端点。GET → 405 如果健康。 | | `me-aps` | GET | `/api/me/aps?limit=1` | 是 | 调用者的自己的 AP 反读(支持 `?since=` 增量同步)。 | | `aircraft` | GET | `/api/aircraft` | 是 | ADS-B 实时快照(顶层数组)。 | | `meshcore` | GET | `/api/meshcore` | 是 | MeshCore 实时快照(顶层数组)。 | | `territories` | GET | `/api/territories` | 是 | 全球帮派凸包(顶层数组)。 | | `member-territories` | GET | `/api/member-territories` | 是 | 基于单元格的网格 + 帮派凸包。5 分钟快照。 | | `leaderboard` | GET | `/api/leaderboard` | 是 | 5 个排行榜。5 分钟快照。 | | `bounties` | GET | `/api/bounties` | 是 | 开放悬赏(最多 200 个)。从 2026-06-03 以后,由于与原始五个处理程序相同的正则表达式级联错误,返回 404;2026-06-04 修复。 | | `team-messages` | GET | `/api/team/messages` | 是 | 调用者的帮派消息列表。 | | `team-messages-id` | GET | `/api/team/messages/1` | 是 | 根据规范仅支持 DELETE — GET → 405 + `Allow: DELETE`(自 2026-06-04 以来)。健康状态是方法判断。 | | `health-asked-for` | GET | `/api/health` | 无 | 尚不存在。在错误 #1 中请求。 | | `stats-leak-check` | GET | `/api/stats` | 无 | 如果正文包含 LSWS 管理遥测指纹,则触发 LEAK。 (locosp 的 2026-05-30 修复已落地 — 端点现在 302 转到登录;v0.6.1 中的规则收紧以检测内容,而不仅仅是状态。) | | `api-sentinel-404-a/b/c` | GET | `/api/` × 3 | 无 | /api/ 404 页面的多数指纹(需要 2-of-3 多数)。 | | `non-api-sentinel-404` | GET | `/` | 无 | 打印非-/api/ 404 页面。 | | `changelog-control` | GET | `/changelog` | 无 | 公共页面可达性控制。 | ## 判决 | 判决 | 含义 | |---|---| | `OK` | 2xx 响应,正文与任何 404 哨兵不同。 | | `AUTH-REQUIRED` | 401。端点是活跃的,并且拒绝具有规范正确的 JSON 形状的密钥。 | | `AUTH-REDIRECT` | `Location` 指向 `/login...` 的 3xx。认证网关正在工作,但端点是通过 Web 会话流程连接的,而不是返回 401 JSON — 对 API 调用者而言是路由形状回退,但不是安全/可用性问题。不会升级到 DEGRADED。 | | `REDIRECT-{n}` | `Location` 不匹配 `/login` 的 3xx(通配符,因此意外的重定向不会伪装成 OK)。 | | `DEAD` | 正文哈希与 /api/ 404 多数哨兵匹配。路由未绑定。 | | `DEAD-NONAPI` | 正文与非-/api/ 404 哨兵匹配。 | | `LEAK` | 正文包含 LiteSpeed 管理遥测指纹 (`lsphp_processes` / `top_domains` / `lsphp`)。在 v0.6.1 中通用化 — 在任何探测中都会触发,而不仅仅是 `stats-leak-check`。由于 locosp 的 2026-05-30 修复落地和 `/api/stats` 开始 302 转到 `/login`,从“stats 返回 200”的规则中收紧。 | | `404` | 404 响应,但正文与哨兵不同。 | | `METHOD` | 405。健康的端点,错误的动词。 | | `ERROR` | 网络超时/URL 错误。 | | `SENTINEL` | 3 个 /api/ 多数哨兵之一,与多数一致。 | | `SENTINEL-OUTLIER` | 与其他 2 个哨兵不一致的 1 个哨兵(例如 CDN 缓存滑动)。通过 2 票多数检测 DEAD;通过 2 票多数检测 DEAD。 | | `SENTINEL-DIVERGED` | 所有 3 个哨兵返回不同的正文。禁用受影响主机的 DEAD 检测;在信任结果之前调查诊断。 | | `SENTINEL-NONAPI` | 非-/api/ 404 指纹探测。 | 总体总结是以下之一: - `HEALTHY` — 没有DEAD,没有ERROR,没有LEAK。 - `UNREACHABLE` — 所有内容都出错。DNS,没有互联网,主机关闭。 - `DEGRADED` — 至少有一个探测DEAD。 - `OUTAGE` — 使用有效密钥的 `/api/me` 是DEAD。整个 API 表面都关闭。 - `…+LEAK` — 当 `/api/stats` 暴露时附加到上述任何一项。 - `…+SENTINEL-DIVERGED` — 当 3 个多数哨兵无法就指纹达成一致时附加。禁用受影响主机的 DEAD 检测;在信任结果之前调查诊断。 退出代码为 DEGRADED/OUTAGE/UNREACHABLE/LEAK/SENTINEL-DIVERGED 时为 `1`,为 HEALTHY 时为 `0`。 ## 按计划运行 将其放入 cron、systemd 定时器或 Windows 任务计划程序。将 `--baseline` 与 `--json` 配对以记录每个快照以供以后趋势分析,或使用 `--watch` 在长时间运行的主机上获取 API 恢复时的单个状态更改通知。 Cron 示例: ``` */5 * * * * cd /opt/wdgwars-api-tester && \ python3 wdgwars_api_tester.py --baseline /var/log/wdgwars/baseline.json \ --json >> /var/log/wdgwars/snapshots.jsonl ``` ## 崩溃感知回退 当 LOCOSP 达到其文档化的每日上限(午夜 UTC 重置)、按 IP 速率限制或传输失败时,`--watch` 模式通过坏判决的份额(`429` 或 `ERROR`)检测到崩溃,并逐步延长轮询之间的睡眠时间,而不是以全速推进。在第一次干净的轮询上重置到正常节奏。 默认:当 ≥30% 的轮询是 `429`/`ERROR` 时触发。连续崩溃轮询的睡眠时间加倍(2×、4×、8×、16×、32× 的 `--watch`),限制在 `--outage-backoff-cap-seconds`(默认 3600 秒)**和**下一个午夜 UTC 的时间。 ``` # 完全禁用功能 python3 wdgwars_api_tester.py --watch 1800 --outage-backoff-threshold 1.01 # 更激进:一旦 10% 的扫描结果不良就退避,最多休眠 4 小时 python3 wdgwars_api_tester.py --watch 1800 \ --outage-backoff-threshold 0.10 \ --outage-backoff-cap-seconds 14400 ``` `DEAD`、`AUTH-REQUIRED`、`AUTH-REDIRECT` 和其他预期的非 OK 判决不计入崩溃份额 — 只有 `429` 和传输级别的 `ERROR` 才计入。 ## 通知渠道 `--watch` 模式支持三个独立的通知路径。使用一个、两个或所有三个同时使用 — 它们不会冲突。 | 标志 | 使用时 | |---|---| | `--alert-telegram` | 您有一个 Telegram 机器人 + 聊天。最简单的设置。 | | `--alert-webhook URL` | 您在 Discord、Slack、n8n、PagerDuty 或任何接受 JSON POST 的服务上。 | | `--exec-on-change CMD` | 以上都不适用 — 电子邮件、短信、一个 Lambda、写入数据库、管道到记录器。 | 任何路径的失败都会在 stderr 中记录警告,但永远不会崩溃 watch 循环或阻止其他路径。 ### Telegram 自分页 在 `--watch` 模式下,工具可以直接在每次状态更改时将帖子发布到 Telegram 聊天。无需外部代理、webhook 服务或警报基础设施 — 使用 stdlib `urllib` 到 Bot API 和聊天 id。 ### 设置 1. 与 Telegram 上的 [@BotFather](https://t.me/BotFather) 联系并创建一个机器人。复制令牌。 2. 将机器人添加到您想要警报的聊天中(DM、群组或频道)。 3. 在该聊天中发送任何消息,然后 `GET https://api.telegram.org/bot/getUpdates` 并读取 `result[0].message.chat.id`(或 `result[0].channel_post.chat.id` 对于频道)。 4. 导出这两个值并传递 `--alert-telegram`: ``` export TELEGRAM_BOT_TOKEN=123456:ABC-DEF... export TELEGRAM_CHAT_ID=-1001234567890 python3 wdgwars_api_tester.py --watch 60 --alert-telegram ``` 或者直接传递:`--telegram-bot-token --telegram-chat-id `。 ### 消息格式 | 转变 | 标题 | |---|---| | 恢复 (`* → HEALTHY`) | `✅ wdgwars API 恢复` | | 诊断损坏 (`+SENTINEL-DIVERGED` 出现) | `🔧 wdgwars-api-tester 诊断损坏` | | 回归(任何更糟的情况) | `🚨 wdgwars API ` | 正文包括 `prev_overall → curr_overall` 转变、按探测的增量(由于 Telegram 的 4096 个字符消息限制,最多 30 行)和判决计数汇总。使用 HTML 解析模式,因此 `` / `` 可以正确渲染。 ### 通用 webhook (`--alert-webhook URL`) 在状态更改时将 JSON 有效负载 POST 到任何 HTTP 端点。有效负载包含多个顶级键,因此相同的 URL 可以用于多个服务,而无需为每个服务设置标志。从 v0.10.0 开始,`text` + `content` 字段包含纯英语散文,因此 Discord/Slack 通道的阅读者可以在没有上下文的情况下理解它们: ``` 🚨 API status changed: all endpoints healthy → some endpoints down What changed since the last check: • team-me/valid: was healthy (HTTP 200), now timing out (>15s) or unreachable • team-id/valid: was healthy (HTTP 200), now timing out (>15s) or unreachable Current snapshot: • 13 endpoints healthy • 27 correctly rejecting unauthorized callers • 2 timed out or unreachable • 2 endpoints missing (404 sentinel match) • 3 background API 404 sentinel (probe of /api/) → Non-upstream probe regressed. Investigate. ``` 完整的有效负载: ``` { "text": "🚨 API status changed: ... (the human-readable string above)", "content": "", "text_machine": "🚨 wdgwars-api-tester: HEALTHY → DEGRADED\n\n\n\nverdicts: DEAD=2, ERROR=2, OK=13, ...", "title": "🚨 API status changed: ...", "kind": "regression", "overall": "DEGRADED", "overall_human": "some endpoints down", "prev_overall": "HEALTHY", "prev_overall_human": "all endpoints healthy", "deltas": ["wdgwars.pl team-me/valid OK/200 -> ERROR/-", "..."], "deltas_human": ["team-me/valid: was healthy (HTTP 200), now timing out ..."], "by_verdict": {"OK": 13, "AUTH-REQUIRED": 27, "ERROR": 2, "DEAD": 2}, "by_verdict_human": ["13 endpoints healthy", "27 correctly rejecting ...", "..."], "action": "Non-upstream probe regressed. Investigate.", "tool": "wdgwars-api-tester", "version": "0.10.0" } ``` - **Discord** 读取 `content`。将任何通道 webhook URL 放入其中。 - **Slack 入站 webhook** 读取 `text`。相同的放入。 - **n8n / Zapier / Make** 可以直接选择结构化字段。 - **PagerDuty Events v2** — 使用 `--exec-on-change`(它期望不同的信封)。 - **自定义 HTTP 处理程序** — 从结构化字段中读取它们需要的任何内容。 - **解析旧语法的工具** — 读取 `text_machine`。格式与 v0.9.0 和更早版本相同。 ### 早晨摘要 (`--digest URL`) 一次性模式,每天运行一次探测一次,并将每日摘要 POST 到 webhook。与在您想要摘要到达的本地小时(通常是 08:00)触发的 systemd 定时器配对,以便 Discord/Slack 通道每天一个可读的“昨晚发生了什么”帖子。与 `--watch` 互斥。 ``` # 将每个 --watch 状态变化附加到状态日志中 python3 wdgwars_api_tester.py --watch 1800 \ --alert-webhook "$DISCORD_LOUD_WEBHOOK" \ --state-log ~/wdgwars-api-tester/lab/state-log.jsonl # 一次性触发摘要(通常来自每日的本地 08:00 systemd 计时器) python3 wdgwars_api_tester.py --digest "$DISCORD_LOUD_WEBHOOK" \ --state-log ~/wdgwars-api-tester/lab/state-log.jsonl ``` 摘要读取的内容: ``` Morning report — 2026-06-04 API status right now: **all endpoints healthy** 50 probes ran. • 14 endpoints healthy • 27 correctly rejecting unauthorized callers • 2 endpoints missing (404 sentinel match) • 3 responding with 405 wrong-verb (endpoint healthy) • 3 background API 404 sentinel (probe of /api/) Last 24 hours: 3 state changes (2 loud, 1 suppressed as LOCOSP upstream flap) • 1× HEALTHY → DEGRADED • 1× DEGRADED → HEALTHY Most-flapped probes: • team-me/valid: 3 transitions → No action needed. ``` 窗口可使用 `--digest-window-hours N`(默认 24)进行配置。 ### 任意命令 (`--exec-on-change CMD`) 在状态更改时运行任何 shell 命令。以下环境变量会导出到子进程: | 环境变量 | 值 | |---|---| | `WDGWARS_OVERALL` | 新的整体判决,例如 `DEGRADED+LEAK` | | `WDGWARS_PREV_OVERALL` | 上一个整体判决 | | `WDGWARS_KIND` | `recovery` / `regression` / `diagnostic-broken` | | `WDGWARS_RECOVERY` | 如果正在过渡到 HEALTHY,则为 `1`,否则为 `0` | | `WDGWARS_DELTAS` | 按探测增量行的新行连接 | | `WDGWARS_VERDICTS` | JSON 编码的 `{verdict: count}` 字典 | 示例: ``` # 每次转换时都发送电子邮件 --exec-on-change 'echo "$WDGWARS_DELTAS" | mail -s "wdgwars: $WDGWARS_OVERALL" me@example.com' # 仅在回归时发送警报(不是恢复,也不是诊断) --exec-on-change '[ "$WDGWARS_KIND" = "regression" ] && /usr/local/bin/page-me.sh "$WDGWARS_OVERALL"' # 转发到现有的内部警报服务 --exec-on-change 'curl -X POST -H "Authorization: Bearer $MY_TOKEN" \ -d "{\"summary\":\"$WDGWARS_OVERALL\",\"verdicts\":$WDGWARS_VERDICTS}" \ https://internal.example.com/alert' ``` 命令以 `shell=True` 和 15 秒超时运行。非零退出代码记录警告,但不会崩溃 watch 循环。 ## 为您自己的服务调整工具 单文件、MIT、仅使用标准库 — 鼓励分叉。结构旨在使这些更改变得容易: - **探测不同的 API。** 编辑 `build_probes()` 以交换端点、方法和预期状态。`DEFAULT_HOSTS` / `ALL_HOSTS` 在顶部更改哪些主机被探测。 - **添加新的探测。** 将 `Probe(...)` 条目追加到 `build_probes()`。每个都自动获得相同的认证变体矩阵和判决注释。 - **添加新的判决。** 编辑 `annotate_verdicts()` 以添加分支,然后添加判决到 `VERDICT_PRIORITY` 以使表排序正常,并添加到 `summary()` 以使其在相关的情况下汇总到整体判决。 - **自定义哨兵机制。** `SENTINEL_PROBES` 和 `_canonical_sentinel()` 定义了多数逻辑。将 `SENTINEL_PROBES` 更改为使用更多哨兵,或重写 `_canonical_sentinel()` 以使用不同的协议规则。 - **不同的通知格式。** 直接编辑 `_format_telegram_text()` 或 `_format_webhook_payload()`。两者都是纯函数,易于单元测试。 如果您分发分叉,MIT 意味着克隆并重命名即可 — 无需归功于上游。 ## 测试 两个套件,都是仅使用标准库。 ### 单元测试(离线,快速) ``` python3 -m unittest test_wdgwars_api_tester ``` 32 个测试,无网络。涵盖判决注释、多数哨兵逻辑、状态签名稳定性、汇总汇总、探测增量检测、Telegram 消息格式化和 webhook 有效负载形状。在不到一秒的时间内运行。 ### 集成测试(默认为离线) ``` python3 integration_test.py # offline — fast, safe, default python3 integration_test.py --live # also runs the live API check INTEGRATION_LIVE=1 python3 integration_test.py # env var equivalent ``` 21 个端到端场景。默认模式是 **离线** — `integration_test.py` 为每个场景启动本地实例 `mock_wdgwars.py`(每个场景一个,在随机端口上)并将测试器指向它们。实际的 `wdgwars.pl`
标签:404 错误, API 测试, DNS枚举, HTTP API, Python, stdlib-only, TCP/IP协议栈, URL发现, 内核驱动, 单文件程序, 安全检测, 差异比较, 开源框架, 性能监控, 情报分析, 持续集成, 数据快照, 无后门, 杀毒引擎, 状态监控, 系统分析, 系统探测, 系统维护, 网络分析, 网络协议, 网络安全工具, 网络安全平台, 网络安全软件, 网络性能, 网络故障, 网络服务, 网络架构, 网络流量, 网络测试工具, 网络测试平台, 网络测试软件, 网络漏洞, 网络监控工具, 网络监控平台, 网络监控软件, 网络管理工具, 网络管理平台, 网络管理软件, 网络设备, 网络诊断, 错误处理