mirror of
https://github.com/ReCloudStudio/WebHooker.git
synced 2026-09-22 16:11:29 +00:00
feat: add gitea/forgejo support
This commit is contained in:
parent
ace036c209
commit
aec0d1a257
43 changed files with 683 additions and 130 deletions
|
|
@ -9,6 +9,7 @@ WebHooker 需要多个密钥才能运行。本地开发时存储在 `.dev.vars`
|
|||
| 变量 | 说明 |
|
||||
| ----------------------- | -------------------------------------------------------- |
|
||||
| `GITHUB_WEBHOOK_SECRET` | GitHub App 设置中的 Webhook 密钥 |
|
||||
| `GITEA_WEBHOOK_SECRET` | Gitea 实例的 Webhook 密钥(仅接收 Gitea webhook 时需要) |
|
||||
| `GITHUB_CLIENT_ID` | App 设置中的 OAuth 客户端 ID |
|
||||
| `GITHUB_CLIENT_SECRET` | App 设置中的 OAuth 客户端密钥 |
|
||||
| `DISCORD_TOKEN` | Discord Bot Token |
|
||||
|
|
@ -30,6 +31,17 @@ WebHooker 需要多个密钥才能运行。本地开发时存储在 `.dev.vars`
|
|||
| `TELEGRAM_WEBHOOK_SECRET` | `POST /telegram/webhook` 验签密钥(X-Telegram-Bot-Api-Secret-Token) | 未设置时不校验 |
|
||||
| `TELEGRAM_RICH_HEADER_HOST` | 外部 rich-header 服务的基础 URL;未设置时使用内置的 `GET /api/richheader` 生成 Telegram 头像卡片 | 内置 `/api/richheader` |
|
||||
|
||||
## Webhook 提供方
|
||||
|
||||
WebHooker 通过同一个 `POST /webhook` 端点接收多个 forge 的 webhook,按请求头自动识别来源;只需把各 forge 的 webhook 指向 `{BASE_URL}/webhook` 即可。
|
||||
|
||||
| 提供方 | 事件请求头 | 签名请求头 | 签名格式 | 密钥 |
|
||||
| ------ | ---------------- | --------------------- | -------------------------- | ----------------------- |
|
||||
| GitHub | `X-GitHub-Event` | `X-Hub-Signature-256` | `sha256=<hex>` HMAC-SHA256 | `GITHUB_WEBHOOK_SECRET` |
|
||||
| Gitea | `X-Gitea-Event` | `X-Gitea-Signature` | 纯 hex HMAC-SHA256 | `GITEA_WEBHOOK_SECRET` |
|
||||
|
||||
Gitea payload 会被归一化为与 GitHub 相同的内部结构,因此路由、过滤器与 28 个格式化器无需改动即可复用;未知或未映射的 Gitea 事件回退到通用格式化器。仓库/提交/用户链接基于 payload 的 `repository.html_url` 生成,会指向你的 Gitea 实例。
|
||||
|
||||
## Web 控制台
|
||||
|
||||
WebHooker 内置了位于 `/admin` 的配置控制台,可在浏览器中管理路由。它由 GitHub OAuth 和管理员白名单保护。
|
||||
|
|
@ -156,17 +168,19 @@ WebHooker 内置了位于 `/admin` 的配置控制台,可在浏览器中管理
|
|||
"id": "backend-team",
|
||||
"name": "后端团队",
|
||||
"adminIds": ["rhencloud"],
|
||||
"owners": ["myorg"]
|
||||
"owners": ["myorg"],
|
||||
"providers": ["github", "gitea"]
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必需 | 说明 |
|
||||
| ---------- | -------- | ---- | ----------------------------------------------------- |
|
||||
| `id` | string | 是 | 小写 id(`a-z0-9`、`-`),由每条路由的 `groupId` 引用 |
|
||||
| `name` | string | 是 | 可读的分组名称 |
|
||||
| `adminIds` | string[] | 是 | 可管理该分组路由的 GitHub 用户 ID 或登录名 |
|
||||
| `owners` | string[] | 否 | 允许事件进入该分组的组织/用户登录名;为空表示不限制 |
|
||||
| `emoji` | boolean | 否 | 是否在该分组消息中显示 emoji(默认 `true`) |
|
||||
| 字段 | 类型 | 必需 | 说明 |
|
||||
| ----------- | -------- | ---- | ----------------------------------------------------------- |
|
||||
| `id` | string | 是 | 小写 id(`a-z0-9`、`-`),由每条路由的 `groupId` 引用 |
|
||||
| `name` | string | 是 | 可读的分组名称 |
|
||||
| `adminIds` | string[] | 是 | 可管理该分组路由的 GitHub 用户 ID 或登录名 |
|
||||
| `owners` | string[] | 否 | 允许事件进入该分组的组织/用户登录名;为空表示不限制 |
|
||||
| `providers` | string[] | 否 | 允许进入该分组的来源平台(`github`、`gitea`);为空表示全部 |
|
||||
| `emoji` | boolean | 否 | 是否在该分组消息中显示 emoji(默认 `true`) |
|
||||
|
||||
### 权限模型
|
||||
|
||||
|
|
@ -174,6 +188,7 @@ WebHooker 内置了位于 `/admin` 的配置控制台,可在浏览器中管理
|
|||
- **分组管理员**(`adminIds`)只能查看和编辑其管理的分组;提交其分组之外的路由返回 `403`。
|
||||
- 分组管理端点通过 `/admin/api/groups/:id/routes` 一次只操作一个分组;`groupId` 由路径参数强制指定。
|
||||
- `owners` 列表限定哪些事件参与者(发送者登录名)的事件会被该分组的路由投递。
|
||||
- `providers` 列表限定哪个 forge(`github`、`gitea`)的事件会被该分组的路由投递。即使组织/用户同名,也可以借此将 GitHub 与 Gitea 分组区分开。
|
||||
|
||||
## 过滤器类型
|
||||
|
||||
|
|
|
|||
|
|
@ -98,6 +98,14 @@ Worker 现在可通过 `https://webhooker.<your-subdomain>.workers.dev` 访问
|
|||
2. 设置 **Webhook URL** 为 `https://webhooker.<your-subdomain>.workers.dev/webhook`
|
||||
3. 设置 **Webhook secret** 与 `GITHUB_WEBHOOK_SECRET` 一致
|
||||
|
||||
### 6.(可选)配置 Gitea Webhook
|
||||
|
||||
1. 在 Gitea 仓库中进入 **设置 → Web 钩子 → 添加 Web 钩子 → Gitea**
|
||||
2. 设置 **目标 URL** 为 `https://webhooker.<your-subdomain>.workers.dev/webhook`
|
||||
3. 设置 **HTTP 方法** 为 `POST`、**Content Type** 为 `application/json`
|
||||
4. 设置 **密钥** 与 `GITEA_WEBHOOK_SECRET` 一致
|
||||
5. 选择要触发的事件(push、议题、拉取请求、发布等)
|
||||
|
||||
## GitHub App 设置
|
||||
|
||||
### 1. 创建 App
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
# 简介
|
||||
|
||||
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 管理。
|
||||
WebHooker 是一个基于 Cloudflare Workers 构建的 GitHub/Gitea webhook 调度器。它接收来自受支持 forge(GitHub、Gitea——更多可通过 `src/providers/` 扩展)的 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) / Telegram (Bot API)
|
||||
GitHub / Gitea Webhook → Cloudflare Worker (Hono)
|
||||
├── POST /webhook → 识别提供方 → 验证 → 去重 → 过滤 → 格式化 → Discord (REST) / Telegram (Bot API)
|
||||
├── POST /discord/interactions → 验证 (Ed25519) → 处理 /gh 斜杠与右键命令
|
||||
├── POST /telegram/webhook → 验证 (secret token) → 处理 /gh 命令
|
||||
├── GET /auth/github → OAuth 流程
|
||||
|
|
@ -27,10 +27,10 @@ GitHub Webhook → Cloudflare Worker (Hono)
|
|||
|
||||
### 数据流
|
||||
|
||||
1. GitHub 发送 webhook 到 `POST /webhook`
|
||||
2. Worker 验证 HMAC-SHA256 签名
|
||||
3. Worker 按 `X-GitHub-Delivery` 去重(KV,短 TTL),丢弃重复投递
|
||||
4. Worker 解析事件类型和载荷
|
||||
1. 某个 forge(GitHub 或 Gitea)发送 webhook 到 `POST /webhook`
|
||||
2. Worker 根据请求头识别提供方(`X-GitHub-Event` / `X-Gitea-Event`)并验证对应提供的 HMAC-SHA256 签名
|
||||
3. Worker 按投递 ID 去重(KV,短 TTL),丢弃重复投递
|
||||
4. Worker 解析事件类型并将载荷归一化为 GitHub 形状的事件
|
||||
5. 根据过滤器(event、repo、actor、action、branch、keyword)与分组所有者限制评估路由
|
||||
6. 匹配的路由触发格式化器函数生成平台中立消息
|
||||
7. 每条消息通过 Discord 或 Telegram REST API 发送到对应路由的目标,并处理速率限制重试;`workflow_run` 进度原地更新。每次尝试都记录到 D1 发送日志
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue