mirror of
https://github.com/ReCloudStudio/WebHooker.git
synced 2026-09-23 00:21:28 +00:00
docs: sync documentation with current codebase
- Update event formatter count 23 -> 28 (add ping, workflow_job, status, deployment, check_suite) - Document Telegram support end-to-end (routes, /gh commands, richheader, secrets) - Fix route schema to use targets array and group fields (owners, emoji) - Correct KV/D1 storage layout (msg:*, i18n:*, D1 links/send_logs) - Note GITHUB_APP_ID/GITHUB_PRIVATE_KEY are unused; drop legacy DISCORD_CHANNEL_ID/PORT/CONFIG_PATH - Remove stale Docker deployment section - Update color table, branch filter compatibility, admin API endpoints - AGENTS.md: add Documentation section requiring doc updates after functional changes
This commit is contained in:
parent
68cda9f178
commit
afe19795b1
25 changed files with 621 additions and 398 deletions
|
|
@ -9,13 +9,16 @@ WebHooker 需要多个密钥才能运行。本地开发时存储在 `.dev.vars`
|
|||
| 变量 | 说明 |
|
||||
| ----------------------- | -------------------------------------------------------- |
|
||||
| `GITHUB_WEBHOOK_SECRET` | GitHub App 设置中的 Webhook 密钥 |
|
||||
| `GITHUB_APP_ID` | GitHub App 的数字 ID |
|
||||
| `GITHUB_PRIVATE_KEY` | App 私钥(PEM 格式,用 `\n` 转义) |
|
||||
| `GITHUB_CLIENT_ID` | App 设置中的 OAuth 客户端 ID |
|
||||
| `GITHUB_CLIENT_SECRET` | App 设置中的 OAuth 客户端密钥 |
|
||||
| `DISCORD_TOKEN` | Discord Bot Token |
|
||||
| `TELEGRAM_TOKEN` | Telegram Bot Token(BotFather 获取)—— Telegram 路由必需 |
|
||||
|
||||
> [!NOTE]
|
||||
> `GITHUB_APP_ID` 与 `GITHUB_PRIVATE_KEY` 当前未被代码使用——OAuth 流程只需要
|
||||
> `GITHUB_CLIENT_ID` / `GITHUB_CLIENT_SECRET`。为兼容性保留在模式中,以备日后启用
|
||||
> GitHub App 认证。
|
||||
|
||||
### 可选密钥
|
||||
|
||||
| 变量 | 说明 | 默认值 |
|
||||
|
|
@ -52,6 +55,7 @@ WebHooker 内置了位于 `/admin` 的配置控制台,可在浏览器中管理
|
|||
| `GET /admin/api/groups/:id/routes` | 列出某分组的路由 |
|
||||
| `PUT /admin/api/groups/:id/routes` | 替换某分组的路由 |
|
||||
| `GET /admin/api/logs` | 发送日志(按可访问路由过滤) |
|
||||
| `GET /admin/api/logs/:id` | 单条发送日志(按权限过滤) |
|
||||
|
||||
控制台支持新增、编辑、删除和开关路由。保存后立即写入 KV `config:routes` 并使配置缓存失效,下一次 webhook 处理即会生效。
|
||||
|
||||
|
|
@ -140,6 +144,7 @@ WebHooker 内置了位于 `/admin` 的配置控制台,可在浏览器中管理
|
|||
| `name` | string | 是 | 可读的分组名称 |
|
||||
| `adminIds` | string[] | 是 | 可管理该分组路由的 GitHub 用户 ID 或登录名 |
|
||||
| `owners` | string[] | 否 | 允许事件进入该分组的组织/用户登录名;为空表示不限制 |
|
||||
| `emoji` | boolean | 否 | 是否在该分组消息中显示 emoji(默认 `true`) |
|
||||
|
||||
### 权限模型
|
||||
|
||||
|
|
@ -167,7 +172,7 @@ WebHooker 内置了位于 `/admin` 的配置控制台,可在浏览器中管理
|
|||
- 在任何过滤器上设置 `"exclude": true` 可反转匹配逻辑(NOT 逻辑)
|
||||
- 非 keyword 过滤器为**精确、不区分大小写**的匹配——不支持通配符(`repo: "org/*"` 不会匹配任何内容)
|
||||
- `keyword` 过滤器支持正则表达式——正则有误或超过 200 个字符时回退到子串匹配
|
||||
- `branch` 过滤器适用于 push、pull_request、pull_request_review、pull_request_review_comment、create/delete、workflow_run 和 code_scanning_alert 事件
|
||||
- `branch` 过滤器适用于 push、pull_request、pull_request_review、pull_request_review_comment、create/delete、workflow_run、workflow_job、check_suite、deployment 和 code_scanning_alert 事件
|
||||
|
||||
### 匹配值
|
||||
|
||||
|
|
@ -180,17 +185,27 @@ WebHooker 内置了位于 `/admin` 的配置控制台,可在浏览器中管理
|
|||
|
||||
## KV 存储布局
|
||||
|
||||
| 键模式 | 值 | TTL |
|
||||
| ------------------------ | --------------------------------------------------- | ------------------ |
|
||||
| `config:routes` | JSON 路由数组 | 永久 |
|
||||
| `config:groups` | JSON 分组数组 | 永久 |
|
||||
| `session:{id}` | 管理员会话 `{ userId, login }` | 7 天 |
|
||||
| `token:{userId}` | `{ userId, accessToken, expiresAt, refreshToken? }` | 0.9 × Token 有效期 |
|
||||
| `token-reverse:{sha256}` | 用于按 Token 反查的用户 id | 0.9 × Token 有效期 |
|
||||
| `discord-link:{userId}` | 与 Discord 用户绑定的 GitHub 用户 id | 永久 |
|
||||
| `state:{hex}` | `{ redirectTo, expiresAt, discordUserId? }` | 600 秒 |
|
||||
| `delivery:{id}` | Webhook 投递 id(去重标记) | 300 秒 |
|
||||
| `logs:send:{ts}-{hex}` | 发送记录 | 1 小时 |
|
||||
| `cmd:guild:{id}` | 已注册命令的服务器 id(去重标记) | 永久 |
|
||||
| `cmd:registered:global` | 全局命令已注册标记(24h 去重) | 1 天 |
|
||||
| `config:discord-app-id` | Discord 应用 id 缓存 | 永久 |
|
||||
| 键模式 | 值 | TTL |
|
||||
| ------------------------------ | ----------------------------------------------------------------------------- | ------------------ |
|
||||
| `config:routes` | JSON 路由数组 | 永久 |
|
||||
| `config:groups` | JSON 分组数组 | 永久 |
|
||||
| `session:{id}` | 管理员会话 `{ userId, login }` | 7 天 |
|
||||
| `token:{userId}` | `{ userId, accessToken, expiresAt, refreshToken? }` | 0.9 × Token 有效期 |
|
||||
| `token-reverse:{sha256}` | 用于按 Token 反查的用户 id | 0.9 × Token 有效期 |
|
||||
| `state:{hex}` | `{ redirectTo, expiresAt, discordUserId?, telegramUserId?, telegramChatId? }` | 600 秒 |
|
||||
| `delivery:{id}` | Webhook 投递 id(去重标记) | 300 秒 |
|
||||
| `msg:{routeId}:{key}:{target}` | 原地更新用消息 id 追踪(如 `workflow_run`) | 7 天 |
|
||||
| `cmd:guild:{id}` | 已注册命令的服务器 id(去重标记) | 永久 |
|
||||
| `cmd:registered:global` | 全局命令已注册标记(24h 去重) | 1 天 |
|
||||
| `config:discord-app-id` | Discord 应用 id 缓存 | 永久 |
|
||||
| `i18n:{lang}` | 翻译覆盖,合并到英文之上 | 永久 |
|
||||
|
||||
## D1 存储布局
|
||||
|
||||
D1 数据库(`DB` 绑定,数据库 `webhooker`)包含三张表:
|
||||
|
||||
| 表 | 用途 |
|
||||
| ---------------- | ---------------------------------------------------------------------- |
|
||||
| `send_logs` | 每次分发尝试一行(路由 id、事件、目标、成功/失败、耗时、错误码、详情) |
|
||||
| `discord_links` | 映射 `discord_user_id` → `github_user_id`,用于 Discord `/gh` 命令 |
|
||||
| `telegram_links` | 映射 `telegram_user_id` → `github_user_id`,用于 Telegram `/gh` 命令 |
|
||||
|
|
|
|||
|
|
@ -25,8 +25,6 @@ npx wrangler kv namespace create KV
|
|||
|
||||
```bash
|
||||
npx wrangler secret put GITHUB_WEBHOOK_SECRET
|
||||
npx wrangler secret put GITHUB_APP_ID
|
||||
npx wrangler secret put GITHUB_PRIVATE_KEY # PKCS#8 PEM(BEGIN PRIVATE KEY)
|
||||
npx wrangler secret put GITHUB_CLIENT_ID
|
||||
npx wrangler secret put GITHUB_CLIENT_SECRET
|
||||
npx wrangler secret put DISCORD_TOKEN
|
||||
|
|
@ -39,15 +37,9 @@ npx wrangler secret put ADMIN_USER_IDS # 逗号分隔的 GitHub ID/登录
|
|||
不存在全局频道密钥。每条路由在 [Web 控制台](/zh/guide/configuration#web-控制台) 中声明各自的目标频道(及可选的子区/thread),因此不需要 `DISCORD_CHANNEL_ID`。
|
||||
:::
|
||||
|
||||
::: warning GitHub App 私钥必须是 PKCS#8
|
||||
GitHub 下发的私钥为 PKCS#1 格式(`BEGIN RSA PRIVATE KEY`)。Cloudflare Workers 的 JWT 签名要求 PKCS#8,需先转换:
|
||||
|
||||
```bash
|
||||
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt \
|
||||
-in your-app.private-key.pem -out gh_pk_pkcs8.pem
|
||||
```
|
||||
|
||||
然后将 `gh_pk_pkcs8.pem` 作为 `GITHUB_PRIVATE_KEY` 上传。
|
||||
::: tip GitHub App ID / 私钥未使用
|
||||
`GITHUB_APP_ID` 与 `GITHUB_PRIVATE_KEY` 当前未被代码使用——OAuth 流程只需要
|
||||
`GITHUB_CLIENT_ID` / `GITHUB_CLIENT_SECRET`。无需设置(也无需进行 PKCS#8 转换)。
|
||||
:::
|
||||
|
||||
Discord 交互通过 HTTPS Interactions Endpoint 送达,需要设置 `DISCORD_PUBLIC_KEY` 并把 **Interactions Endpoint URL** 指向 `https://your-domain/discord/interactions`。参见下方 [Interactions Endpoint](#interactions-endpoint)。
|
||||
|
|
@ -79,8 +71,8 @@ Worker 现在可通过 `https://webhooker.<your-subdomain>.workers.dev` 访问
|
|||
3. 设置权限:
|
||||
- **Repository permissions**: Contents (read)、Issues (write)、Pull requests (write)、Metadata (read)、Checks (read)、Deployments (read)、Discussions (read)、Code scanning alerts (read)、Dependabot alerts (read)
|
||||
- **Organization permissions**: Members (read) —— 如果需要
|
||||
4. 订阅事件(全部 23 种支持的事件):
|
||||
- Push、Pull request、Issues、Issue comment、Workflow run、Release、Create、Delete、Star、Fork、Check run、Pull request review、Pull request review comment、Commit comment、Deployment status、Member、Label、Milestone、Discussion、Discussion comment、Repository、Code scanning alert、Dependabot alert
|
||||
4. 订阅事件(全部 28 种支持的事件):
|
||||
- Push、Pull request、Issues、Issue comment、Workflow run、Workflow job、Status、Deployment、Deployment status、Ping、Release、Create、Delete、Star、Fork、Check run、Check suite、Pull request review、Pull request review comment、Commit comment、Member、Label、Milestone、Discussion、Discussion comment、Repository、Code scanning alert、Dependabot alert
|
||||
5. 生成私钥 → 将内容保存到 `GITHUB_PRIVATE_KEY` 环境变量
|
||||
|
||||
### 2. 安装 App
|
||||
|
|
@ -120,6 +112,22 @@ Worker 现在可通过 `https://webhooker.<your-subdomain>.workers.dev` 访问
|
|||
|
||||
用户运行 `/gh login` 绑定自己的 GitHub 账号,即可以本人身份评论 issue/PR。完整命令说明见 [README](https://github.com/ReCloudStudio/WebHooker#bot-commands-comment-on-github-as-yourself)。
|
||||
|
||||
## Telegram 机器人配置
|
||||
|
||||
1. 用 [@BotFather](https://t.me/BotFather) 创建机器人,将 Token 复制到 `TELEGRAM_TOKEN`。
|
||||
2. (可选)设置 `TELEGRAM_WEBHOOK_SECRET`;webhook 注册时会作为 `secret_token` 传给 Telegram,`POST /telegram/webhook` 使用时间安全比较校验。
|
||||
3. Worker 会在定时任务中自动同步 webhook(`setWebhook` 指向 `{BASE_URL}/telegram/webhook`),因此无需手动调用 `setWebhook`——只需确保 `BASE_URL` 已设置。
|
||||
4. 将机器人加入群组(或启用话题),在路由配置中用 `chatId` / `topicId` 指定目标。
|
||||
|
||||
在 Telegram 中,`/gh` 命令通过在通知消息上**回复**来使用:
|
||||
|
||||
- `/gh login` — 绑定你的 GitHub 账号(返回 OAuth 链接)
|
||||
- `/gh logout` — 解除绑定
|
||||
- `/gh comment <内容>` — 回复一条 issue/PR 通知,以本人身份评论
|
||||
- `/gh merge` / `/gh close` — 回复一条 PR 通知,合并/关闭该 PR
|
||||
|
||||
头像使用内置 `GET /api/richheader` 渲染为链接预览卡片(可用 `TELEGRAM_RICH_HEADER_HOST` 覆盖)。
|
||||
|
||||
## 自定义域名(可选)
|
||||
|
||||
要使用自定义域名替代 `*.workers.dev`:
|
||||
|
|
@ -128,13 +136,5 @@ Worker 现在可通过 `https://webhooker.<your-subdomain>.workers.dev` 访问
|
|||
2. 添加自定义域名或路由
|
||||
3. 更新 `BASE_URL` 以匹配
|
||||
|
||||
## Docker
|
||||
|
||||
提供 Dockerfile 用于容器化部署(例如在反向代理后面):
|
||||
|
||||
```bash
|
||||
docker build -t webhooker .
|
||||
docker run -p 8787:8787 --env-file .env webhooker
|
||||
```
|
||||
|
||||
注意:Docker 模式下不包含 KV 等 Cloudflare 存储。完整功能请使用 Cloudflare 部署。
|
||||
> [!NOTE]
|
||||
> 本项目是一个 Cloudflare Worker,依赖 `wrangler.jsonc` 中声明的 KV 与 D1 绑定,无法作为独立的 Node/容器进程运行。
|
||||
|
|
|
|||
|
|
@ -84,13 +84,16 @@
|
|||
|
||||
匹配事件涉及的分支。何种字段算作「分支」取决于事件类型:
|
||||
|
||||
| 事件 | 提取的分支 |
|
||||
| --------------------------- | ------------------------------ |
|
||||
| `push` | 推送到的目标分支 |
|
||||
| `pull_request`(及 review) | 拉取请求的 **head**(源)分支 |
|
||||
| `create` / `delete` | 创建/删除的分支或标签 |
|
||||
| `workflow_run` | 工作流运行所在的 `head_branch` |
|
||||
| `code_scanning_alert` | 告警所属的分支 |
|
||||
| 事件 | 提取的分支 |
|
||||
| --------------------------- | ----------------------------------- |
|
||||
| `push` | 推送到的目标分支 |
|
||||
| `pull_request`(及 review) | 拉取请求的 **head**(源)分支 |
|
||||
| `create` / `delete` | 创建/删除的分支或标签 |
|
||||
| `workflow_run` | 工作流运行所在的 `head_branch` |
|
||||
| `workflow_job` | 作业运行所在的 `head_branch` |
|
||||
| `check_suite` | 检查套件的 `head_branch` |
|
||||
| `deployment` | 部署引用(去除 `refs/heads/` 前缀) |
|
||||
| `code_scanning_alert` | 告警所属的分支 |
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
|
|||
|
|
@ -29,8 +29,6 @@ cp .env.example .dev.vars
|
|||
|
||||
```bash
|
||||
GITHUB_WEBHOOK_SECRET=your-webhook-secret
|
||||
GITHUB_APP_ID=your-app-id
|
||||
GITHUB_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
|
||||
GITHUB_CLIENT_ID=your-client-id
|
||||
GITHUB_CLIENT_SECRET=your-client-secret
|
||||
DISCORD_TOKEN=your-bot-token
|
||||
|
|
@ -40,7 +38,7 @@ BASE_URL=http://localhost:8787
|
|||
```
|
||||
|
||||
::: tip
|
||||
`GITHUB_PRIVATE_KEY` 必须是 **PKCS#8** 格式(`BEGIN PRIVATE KEY`)。用 `openssl pkcs8 -nocrypt -in app.pem -out pkcs8.pem` 转换 GitHub 下发的 PKCS#1 私钥。目标频道在 Web UI 中按路由设置,因此不需要 `DISCORD_CHANNEL_ID`。若要在本地启用 `/gh` 命令,请在开发者门户复制 **Public Key** 填入 `DISCORD_PUBLIC_KEY`,并把 Interactions Endpoint URL 设为 `http://localhost:8787/discord/interactions`。
|
||||
`GITHUB_APP_ID` / `GITHUB_PRIVATE_KEY` 未被代码使用(OAuth 流程只需要 Client ID/Secret),可省略。目标频道在 Web UI 中按路由设置,因此不需要 `DISCORD_CHANNEL_ID`。若要在本地启用 `/gh` 命令,请在开发者门户复制 **Public Key** 填入 `DISCORD_PUBLIC_KEY`,并把 Interactions Endpoint URL 设为 `http://localhost:8787/discord/interactions`。
|
||||
:::
|
||||
|
||||
::: warning
|
||||
|
|
|
|||
|
|
@ -1,27 +1,29 @@
|
|||
# 简介
|
||||
|
||||
WebHooker 是一个基于 Cloudflare Workers 构建的 GitHub webhook 调度器。它接收 GitHub webhook 事件,应用可配置的过滤器,将事件格式化为丰富的 Discord 嵌入消息,并通过 Discord REST API 投递到 Discord 频道或帖子。Discord 内的 `/gh` 交互通过 HTTPS Interactions Endpoint(Ed25519 验签)送达。路由通过内置的 Web UI 管理。
|
||||
WebHooker 是一个基于 Cloudflare Workers 构建的 GitHub webhook 调度器。它接收 GitHub webhook 事件,应用可配置的过滤器,将事件格式化为富消息,并通过各自 REST API 投递到 Discord 频道/子区(embed)与 Telegram 群组/话题(HTML)。Discord 内的 `/gh` 交互通过 HTTPS Interactions Endpoint(Ed25519 验签)送达;Telegram 的 `/gh` 命令通过 Telegram webhook 送达。路由与分组通过内置的 Web UI 管理。
|
||||
|
||||
## 架构
|
||||
|
||||
```text
|
||||
GitHub Webhook → Cloudflare Worker (Hono)
|
||||
├── POST /webhook → 验证 → 去重 → 过滤 → 格式化 → Discord (REST API)
|
||||
├── POST /webhook → 验证 → 去重 → 过滤 → 格式化 → Discord (REST) / Telegram (Bot API)
|
||||
├── POST /discord/interactions → 验证 (Ed25519) → 处理 /gh 斜杠与右键命令
|
||||
├── POST /telegram/webhook → 验证 (secret token) → 处理 /gh 命令
|
||||
├── GET /auth/github → OAuth 流程
|
||||
├── GET /api/richheader → Telegram 头像链接预览卡片
|
||||
├── POST /api/* → 用户操作 (Bearer Token 鉴权)
|
||||
├── /admin → 路由与发送日志 Web UI(管理员会话)
|
||||
├── /admin → 路由、分组与发送日志 Web UI(管理员会话)
|
||||
└── GET /health → 健康检查
|
||||
|
||||
POST /discord/interactions → 验证 (Ed25519) → 处理 /gh 斜杠与右键命令
|
||||
```
|
||||
|
||||
### 组件
|
||||
|
||||
| 组件 | 职责 |
|
||||
| ------------------------- | --------------------------------------------------------------------------------------------------------- |
|
||||
| **Cloudflare Worker** | HTTP 入口、签名验证、投递去重、事件解析、路由匹配、REST 发送 |
|
||||
| **Interactions Endpoint** | 验证 Ed25519 签名并处理 `/gh` 交互(斜杠命令、右键菜单、按钮、modal) |
|
||||
| **KV** | Token 存储 (`token:{userId}`)、OAuth 状态 (`state:{hex}`)、路由配置 (`config:routes`)、发送日志、投递去重 |
|
||||
| 组件 | 职责 |
|
||||
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Cloudflare Worker** | HTTP 入口、签名验证、投递去重、事件解析、路由匹配、平台分发 |
|
||||
| **Interactions Endpoint** | 验证 Ed25519 签名并处理 `/gh` 交互(斜杠命令、右键菜单、按钮、modal) |
|
||||
| **KV** | Token 存储 (`token:{userId}`)、OAuth 状态 (`state:{hex}`)、路由配置 (`config:routes`)、分组配置 (`config:groups`)、管理员会话、投递去重、消息更新追踪 (`msg:*`) |
|
||||
| **D1** | 发送日志 (`send_logs`)、Discord↔GitHub 绑定 (`discord_links`)、Telegram↔GitHub 绑定 (`telegram_links`) |
|
||||
|
||||
### 数据流
|
||||
|
||||
|
|
@ -29,18 +31,19 @@ POST /discord/interactions → 验证 (Ed25519) → 处理 /gh 斜杠与右键
|
|||
2. Worker 验证 HMAC-SHA256 签名
|
||||
3. Worker 按 `X-GitHub-Delivery` 去重(KV,短 TTL),丢弃重复投递
|
||||
4. Worker 解析事件类型和载荷
|
||||
5. 根据过滤器评估路由(event、repo、actor、action、branch、keyword)
|
||||
6. 匹配的路由触发格式化器函数生成 Discord 嵌入消息
|
||||
7. 每条消息通过 Discord REST API 发送到对应路由的目标频道/帖子,并处理速率限制重试,结果记录到发送日志
|
||||
5. 根据过滤器(event、repo、actor、action、branch、keyword)与分组所有者限制评估路由
|
||||
6. 匹配的路由触发格式化器函数生成平台中立消息
|
||||
7. 每条消息通过 Discord 或 Telegram REST API 发送到对应路由的目标,并处理速率限制重试;`workflow_run` 进度原地更新。每次尝试都记录到 D1 发送日志
|
||||
|
||||
## 技术栈
|
||||
|
||||
- **运行时**: Cloudflare Workers
|
||||
- **HTTP 框架**: Hono
|
||||
- **Discord 投递**: Discord REST API(交互通过 Ed25519 验签的 HTTPS Interactions Endpoint)
|
||||
- **Telegram 投递**: Telegram Bot API(webhook 带可选 secret-token 校验)
|
||||
- **Web UI**: Nuxt 3 静态 SPA,由 Worker 资源托管
|
||||
- **存储**: Cloudflare KV
|
||||
- **鉴权**: Web Crypto API (HMAC-SHA256)、jose (JWT)、octokit (GitHub API)
|
||||
- **存储**: Cloudflare KV + D1
|
||||
- **鉴权**: Web Crypto API (HMAC-SHA256、Ed25519)、octokit (GitHub API)、jose(依赖)
|
||||
- **语言**: TypeScript
|
||||
|
||||
## 许可证
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue