WebHooker/README.zh.md

191 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# WebHooker
GitHub / Gitea webhook → Discord / Telegram 分发服务。通过 Cloudflare Workers 接收 webhook 事件,应用过滤器,将格式化消息路由到 Discord 频道/子区与 Telegram 群组/话题。各 forge 适配器位于 `server/lib/providers/`(目前支持 GitHub + GiteaGitLab 等可后续扩展)。
## 功能特性
- **28 种事件格式化** — push、pull_request、issues、issue_comment、workflow_run、workflow_job、status、deployment、deployment_status、check_run、check_suite、ping、release、create、delete、star、fork、pull_request_review、pull_request_review_comment、commit_comment、member、label、milestone、discussion、discussion_comment、repository、code_scanning_alert、dependabot_alert+ 通用回退,+ `custom` 自定义 webhook
- **多平台 webhook** — GitHub`X-Hub-Signature-256`)与 Gitea`X-Gitea-Signature`)共用 `/webhook` 端点,自动识别来源平台
- **分组级 webhook 入口** — 每个分组可拥有独立的 `POST /webhook/{groupId}` URL + secretGitea、classic GitHub webhook以及用 `X-WebHooker-Signature` 签名的任意自定义 JSON可选的 timestamp+nonce 重放防护)
- **GitHub App 租户隔离** — 将分组绑定到 GitHub App 安装 ID只有该组织/用户的事件才能进入该分组
- HMAC-SHA256 签名验证Web Crypto API
- 按事件类型、仓库、操作人、操作、分支、关键词过滤(支持 `*`/`?` 通配符与 `/正则/`
- 富消息:颜色编码、作者头像、字段、时间戳——渲染为 Discord embed 与 Telegram HTML
- 路由到 Discord 频道/子区与 Telegram 群组/话题(一条路由可多目标)
- `workflow_run` / `check_run` 进度**原地编辑**同一条消息(运行推进时更新),两个平台均支持
- **分组级 Webhook 日志频道** —— 为分组指定一个 Discord 频道/子区或 Telegram 群组/话题,该分组路由每次分发 webhook 都会向其中发送摘要(每条「路由 × 目标」一行,✅/❌ 结果)
- GitHub OAuth 用户授权(评论、编辑评论、删除评论、合并、关闭、反应)
- **Web 配置控制台**`/admin`)— 通过 GitHub OAuth + 管理员白名单管理路由与分组、查看发送日志
- **Discord Interactions Endpoint**Ed25519 验签)支持 `/gh` 斜杠命令、消息右键菜单命令、PR 合并/关闭按钮与评论 modal
- **Telegram `/gh` 命令**login/logout/comment/merge/close通过 Telegram webhook 接收,头像以链接预览卡片呈现
- Cloudflare KV 存储 token/状态/配置/会话 + D1 存储发送日志与平台账号绑定
- **Cloudflare Queues 异步投递** —— 绑定 `QUEUE` 时,已验签的 webhook 会入队到 `webhooker-delivery`由消费者分发带指数退避重试5s/30s/2m/10m与死信队列`webhooker-delivery-dlq`);超大负载暂存于 KV。未绑定则保持同步分发
- 优雅降级Discord 不可用时仅 webhook 模式)
## 架构
```text
GitHub Webhook → Cloudflare Worker (Nuxt 4 / Nitro)
├── POST /webhook → 验证 → 去重 → 入队 (Queue) → 分发 → Discord (REST) / Telegram (Bot API)
├── POST /discord/interactions → 验证 (Ed25519) → 处理命令/按钮/modal
├── POST /telegram/webhook → 验证 (secret token) → 处理 /gh 命令
├── GET /auth/github → OAuth 流程
├── GET /api/richheader → Telegram 头像链接预览卡片
├── POST /api/* → 用户操作Bearer token 鉴权)
├── /admin → 路由、分组与发送日志 Web UI
└── GET /health → 健康检查
```
- **Cloudflare Worker** — HTTP 入口、签名验证、路由分发
- **Interactions Endpoint** — HTTPS 回调(无 Discord Gateway 连接、无 Durable Objectbot 保持离线,命令通过 API 注册
- **KV** — Token 存储(`token:{userId}`、OAuth state`state:{hex}`)、路由配置(`config:routes`)、分组配置(`config:groups`)、管理员会话(`session:{id}`)、投递去重(`delivery:{provider}:{groupId}:{id}`)、投递状态(`delivery-state:*`)、消息更新追踪(`msg:*`
- **D1** — 发送日志(`send_logs`、Discord↔GitHub 绑定(`discord_links`、Telegram↔GitHub 绑定(`telegram_links`
- **Queue** — 绑定 `QUEUE` 时异步投递:`webhooker-delivery`(指数退避重试)+ 死信队列 `webhooker-delivery-dlq`;超大负载暂存于 KV`queue:payload:*`
## 快速开始
```bash
bun install # 包管理器为 bun锁文件bun.lock
cp .env.example .dev.vars # 填写本地开发密钥
bun run build # 先构建生产产物wrangler dev 运行的是构建产物)
bunx wrangler dev # 启动本地开发服务器
```
## 配置
### 密钥(本地用 `.dev.vars`,生产用 Worker Secrets
| 变量 | 说明 |
| --------------------------- | --------------------------------------------------------------------------- |
| `GITHUB_WEBHOOK_SECRET` | GitHub webhook 密钥 |
| `GITEA_WEBHOOK_SECRET` | Gitea webhook 密钥(仅接收 Gitea webhook 时需要) |
| `GITHUB_APP_ID` | GitHub App ID用于 App 安装流程解析安装所属账号) |
| `GITHUB_PRIVATE_KEY` | App 私钥PKCS#8 PEM用于 App 安装流程,可选) |
| `GITHUB_CLIENT_ID` | OAuth Client ID |
| `GITHUB_CLIENT_SECRET` | OAuth Client Secret |
| `DISCORD_TOKEN` | 机器人 token |
| `DISCORD_PUBLIC_KEY` | Discord 应用的公钥(开发者门户获取)—— 交互功能必需 |
| `DISCORD_APPLICATION_ID` | Discord 应用 ID可选省略时通过 `GET /oauth2/applications/@me` 自动获取) |
| `TELEGRAM_TOKEN` | Telegram Bot TokenBotFather 获取)—— Telegram 路由必需 |
| `TELEGRAM_WEBHOOK_SECRET` | 可选;`POST /telegram/webhook` 的验签密钥 |
| `TELEGRAM_RICH_HEADER_HOST` | 可选;覆盖内置 `GET /api/richheader` 的 Telegram 头像卡片地址 |
| `BASE_URL` | 公网地址(用于 OAuth 回调与 Telegram webhook 同步) |
| `ADMIN_USER_IDS` | 允许访问 `/admin` 的 GitHub 用户 ID或登录名逗号分隔 |
| `ALLOW_SELF_SIGNUP` | 设为 `1` 时,无权限的 GitHub 用户首次登录自动获得个人分组(默认关闭) |
| `AUDIT_RETENTION_DAYS` | 定时清理时审计日志的保留天数(默认 90 |
| `NUXT_PUBLIC_DOCS_URL` | 可选;落地页使用的文档站点 URL |
| `NUXT_PUBLIC_REPO_URL` | 可选;落地页使用的 GitHub 仓库 URL |
| `NUXT_PUBLIC_LEGAL_CONTACT` | 可选;`/terms``/privacy` 页面展示的联系方式 |
### 路由配置
路由存储在 KV`config:routes`JSON 格式)。**没有默认路由**——每条路由(包括目标)都必须显式定义,可通过 Web 控制台(`/admin`)或直接向 KV 存储 JSON 数组。一条路由可携带多个 `targets`,因此一个规则可以同时转发到多个频道:
```json
[
{
"id": "all-push",
"name": "Push 事件",
"enabled": true,
"groupId": "default",
"filters": [{ "type": "event", "match": "push" }],
"stop": true,
"targets": [
{ "platform": "discord", "channelId": "频道ID" },
{ "platform": "telegram", "chatId": "-1001234567890" }
]
}
]
```
`target.platform` 选择推送目标:`discord`(默认)或 `telegram`。Discord 目标需 `target.channelId`(可选 `threadId` 指向子区Telegram 目标需 `target.chatId`(可选 `topicId` 指向话题)。路由隶属于**分组**KV `config:groups`),分组用于限定管理权限,并可限制哪些组织/用户的事件流入。完整模式见[路由与目标](https://webhooker.docs.worldexecute.me/zh/guide/routes)与[分组与访问控制](https://webhooker.docs.worldexecute.me/zh/guide/groups)指南。
### Web 控制台(`/admin`
内置的配置控制台让你在浏览器中管理路由与分组(新增 / 编辑 / 删除 / 开关 / 排序)、查看发送日志、管理组成员与邀请链接、阅读审计日志——无需操作 KV
1. 设置 `ADMIN_USER_IDS` 为允许管理控制台的 GitHub 用户 ID或登录名例如 `ADMIN_USER_IDS=12345,RhenCloud`
2. 访问 `/admin` 并用 GitHub 登录。无任何权限的用户收到 `403`——除非开启 `ALLOW_SELF_SIGNUP=1`(自动获得个人分组)或通过分组邀请链接加入。
3. 修改会立即写入 KVwebhook 管线随即生效。
`/admin/logout` 退出登录。每个分组都有带角色的 `members``owner` / `admin` / `viewer`);所有管理操作(登录、分组/路由/成员/邀请变更)都会写入 D1 `audit_logs` 表。
### 过滤器类型
所有过滤器均支持纯文本、`*`/`?` 通配符与 `/正则/`(不区分大小写);设置 `exclude: true` 可取反。过滤器还可通过路由上可选的 `ast``all` / `any` / `not` 节点)组合为 AST以表达默认 AND 列表之外的布尔组合。模式语法与完整过滤器参考见[过滤器教程](https://webhooker.docs.worldexecute.me/zh/guide/filters)。
## API
### 健康检查
- `GET /health` — 返回 `{"status": "ok"}`
### OAuth
- `GET /auth/github` — 发起 GitHub OAuth 授权(重定向到 GitHub
- `GET /auth/github/callback` — OAuth 回调(交换 code 为 token管理员会话 / Discord 绑定 / Telegram 绑定)
- `DELETE /auth/token/:userId` — 撤销用户 token
### 操作接口(需要 `Authorization: Bearer <token>` 头)
- `POST /api/comment` — 创建 issue 评论
- `POST /api/merge` — 合并 PR
- `POST /api/close` — 关闭 PR
- `POST /api/react` — 添加 issue 反应
### 管理接口(需要管理员 OAuth 会话)
- `GET /admin` — 配置控制台页面
- `GET /admin/login` — 开始管理员登录GitHub OAuth
- `GET /admin/logout` — 退出登录
- `GET /admin/invite?token=…` — 接受分组邀请(浏览器页面)
- `GET /admin/api/routes` — 列出路由
- `PUT /admin/api/routes` — 替换路由(按分组 owner/admin 权限)
- `GET /admin/api/groups` — 列出分组 + 你的角色
- `PUT /admin/api/groups` — 替换分组超管全量owner 仅自己的组)
- `GET /admin/api/groups/:groupId/routes` — 列出某分组的路由
- `PUT /admin/api/groups/:groupId/routes` — 替换某分组的路由
- `POST /admin/api/groups/:groupId/invites` — 创建邀请链接owner
- `GET /admin/api/groups/:groupId/invites` — 列出待接受邀请owner
- `DELETE /admin/api/invites/:token` — 撤销邀请owner
- `GET /admin/api/audit` — 审计日志(按权限过滤)
- `GET /admin/api/me` — 当前会话 / 权限范围 / 角色
- `GET /admin/api/logs` — 发送日志(按权限过滤)
- `GET /admin/api/logs/:id` — 单条发送日志
- `GET /admin/api/metrics` — 投递指标(总计、失败率、按平台/事件/状态、最近失败)
- `GET /admin/api/delivery/:deliveryId` — 单次投递的全部发送日志
## 配置教程
- **GitHub App** — 创建应用、订阅事件、配置 OAuth 与 _Setup URL_(租户隔离):见 [GitHub App 配置](https://webhooker.docs.worldexecute.me/zh/guide/deployment#github-app-设置)
- **Discord 机器人** — 创建机器人、以 `applications.commands` scope 邀请(组合权限整数 `274877910016`)、配置 Interactions Endpoint见 [Discord Bot 配置](https://webhooker.docs.worldexecute.me/zh/guide/deployment#discord-bot-设置)。bot 从不连接 Discord Gateway因此显示为**离线**——消息推送不受影响(始终走 REST
- **Telegram 机器人** — 用 [@BotFather](https://t.me/BotFather) 创建机器人,设置 `TELEGRAM_TOKEN`(可选 `TELEGRAM_WEBHOOK_SECRET`webhook 由定时任务自动同步:见 [Telegram 机器人配置](https://webhooker.docs.worldexecute.me/zh/guide/deployment#telegram-机器人配置)
- **部署** — KV 命名空间、D1 数据库与迁移、可选 Queues、密钥、部署见[部署指南](https://webhooker.docs.worldexecute.me/zh/guide/deployment)
### Bot 指令(以本人身份评论 GitHub
bot 通过定时任务(每 5 分钟)同步注册原生的**斜杠命令**与**消息右键菜单命令**按服务器注册以获得即时可用性并全局注册24h 去重,约 1 小时传播)。执行 `/gh login` 后即可评论 issue/PR、编辑/删除自己的评论,并通过按钮合并/关闭 PR——所有回复均为临时消息仅你可见权限交由 GitHub 判定。
```
/gh login /gh logout
/gh comment add|edit|del link:<链接> (或右键通知 → 应用 → GitHub: 添加/编辑/删除评论)
```
完整参考见[机器人命令指南](https://webhooker.docs.worldexecute.me/zh/guide/commands)。
## 开发命令
```bash
bun run dev # Nuxt 开发服务器HMR
bun run typecheck # 类型检查
bun run lint # ESLint
bun test # 单元测试
```
## 支持的事件
28 个事件格式化器push、pull_request、issues、workflow_run、release 等)外加 `custom` webhook不支持的事件回退到通用格式化器。带嵌入亮点的完整表格见[支持的事件](https://webhooker.docs.worldexecute.me/zh/events/supported)。
## 许可证
MIT