mirror of
https://github.com/ReCloudStudio/WebHooker.git
synced 2026-09-23 00:21:28 +00:00
refactor: replace Discord Gateway DO with Interaction Endpoint
This commit is contained in:
parent
9bb9cb1444
commit
d540d465d1
27 changed files with 834 additions and 964 deletions
|
|
@ -14,6 +14,7 @@ https://your-worker.workers.dev
|
|||
| -------- | ------------------------------ | ------------ | ------------------------ |
|
||||
| `GET` | `/health` | 无 | 健康检查 |
|
||||
| `POST` | `/webhook` | HMAC 签名 | GitHub webhook 接入 |
|
||||
| `POST` | `/discord/interactions` | Ed25519 签名 | Discord 交互(斜杠命令、按钮、modal) |
|
||||
| `GET` | `/auth/github` | 无 | 启动 GitHub OAuth 流程 |
|
||||
| `GET` | `/auth/github/callback` | 无 | OAuth 回调 |
|
||||
| `DELETE` | `/auth/token/:userId` | 无 | 撤销用户 Token |
|
||||
|
|
|
|||
|
|
@ -14,14 +14,14 @@ npm run dev # 启动本地开发服务器
|
|||
|
||||
```text
|
||||
src/
|
||||
├── index.ts # CF Workers 入口 (fetch + scheduled),导出 DiscordGateway DO
|
||||
├── index.ts # CF Workers 入口 (fetch + scheduled),scheduled = 命令同步
|
||||
├── types.ts # Env、Config、Route、Filter、WebhookEvent、FormattedMessage
|
||||
├── config.ts # 从 KV 加载路由(未设置时返回 []),从 env 构建 Config
|
||||
├── server.ts # Hono 应用: /health、/webhook,挂载 /auth、/admin + /
|
||||
├── server.ts # Hono 应用: /health、/webhook、/discord/interactions,挂载 /auth、/admin + /
|
||||
├── webhook.ts # HMAC 验证 (Web Crypto)、parseEvent、extractBranch、matchRoute
|
||||
├── discord.ts # 通过 Discord REST 分发(启用 Gateway 时走 DO RPC)、initGateway (scheduled)
|
||||
├── discord.ts # 通过 Discord REST 分发 (sendMessage)
|
||||
├── discord-rest.ts # Discord REST sendMessage,带重试和限流处理
|
||||
├── discord-gateway.ts # Durable Object: Discord Gateway WS、心跳、频道缓存、发送
|
||||
├── discord-interactions.ts # Ed25519 验签 + 交互处理 (/gh、按钮、modal) + 命令注册
|
||||
├── formatter.ts # 23 种事件格式化器 + 通用回退
|
||||
├── github-oauth.ts # OAuth URL、回调 Token 交换、getUserOctokit
|
||||
├── oauth-routes.ts # GET /auth/github、回调、DELETE /token/:userId (KV 状态)
|
||||
|
|
|
|||
|
|
@ -17,11 +17,12 @@ WebHooker 需要多个密钥才能运行。本地开发时存储在 `.dev.vars`
|
|||
|
||||
### 可选密钥
|
||||
|
||||
| 变量 | 说明 | 默认值 |
|
||||
| ------------------------- | -------------------------------------------------------------------------- | ----------------------- |
|
||||
| `BASE_URL` | OAuth 回调的公开 URL | `http://localhost:8787` |
|
||||
| `ADMIN_USER_IDS` | 允许访问 WebUI 的 GitHub 用户 ID(或登录名),逗号分隔 | 未设置时 WebUI 关闭 |
|
||||
| `DISCORD_GATEWAY_ENABLED` | 设为 `true` 连接 Discord Gateway(bot 在线状态);不启用也能通过 REST 推送 | `false` |
|
||||
| 变量 | 说明 | 默认值 |
|
||||
| ------------------------ | ------------------------------------------------------ | ----------------------- |
|
||||
| `BASE_URL` | OAuth 回调的公开 URL | `http://localhost:8787` |
|
||||
| `ADMIN_USER_IDS` | 允许访问 WebUI 的 GitHub 用户 ID(或登录名),逗号分隔 | 未设置时 WebUI 关闭 |
|
||||
| `DISCORD_PUBLIC_KEY` | Discord 应用的公钥(开发者门户获取),交互功能必需 | 未设置时交互返回 401 |
|
||||
| `DISCORD_APPLICATION_ID` | Discord 应用 ID;省略时自动获取 | 自动获取 |
|
||||
|
||||
## Web 控制台
|
||||
|
||||
|
|
@ -181,3 +182,6 @@ WebHooker 内置了位于 `/admin` 的配置控制台,可在浏览器中管理
|
|||
| `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 缓存 | 永久 |
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ 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
|
||||
npx wrangler secret put DISCORD_PUBLIC_KEY # Discord 应用的公钥(开发者门户获取),交互功能必需
|
||||
npx wrangler secret put ADMIN_USER_IDS # 逗号分隔的 GitHub ID/登录名,允许进入 Web UI
|
||||
```
|
||||
|
||||
|
|
@ -48,7 +49,7 @@ openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt \
|
|||
然后将 `gh_pk_pkcs8.pem` 作为 `GITHUB_PRIVATE_KEY` 上传。
|
||||
:::
|
||||
|
||||
Discord Gateway 是可选的。在 `wrangler.jsonc` 的 `vars` 中设置 `DISCORD_GATEWAY_ENABLED`(默认为 `"false"`)。参见下方 [Gateway(可选)](#gateway可选)。
|
||||
Discord 交互通过 HTTPS Interactions Endpoint 送达,需要设置 `DISCORD_PUBLIC_KEY` 并把 **Interactions Endpoint URL** 指向 `https://your-domain/discord/interactions`。参见下方 [Interactions Endpoint](#interactions-endpoint)。
|
||||
|
||||
### 3. 部署
|
||||
|
||||
|
|
@ -106,14 +107,17 @@ Worker 现在可通过 `https://webhooker.<your-subdomain>.workers.dev` 访问
|
|||
|
||||
5. 在 Web UI(`/admin`)中**按路由**配置目标频道——无需全局频道 ID。
|
||||
|
||||
### Gateway(可选)
|
||||
### Interactions Endpoint
|
||||
|
||||
消息通过 Discord **REST API** 发送,因此仅凭 `DISCORD_TOKEN` 即可推送。Gateway 连接仅用于:(a) 让 Bot 显示为**在线**,(b) 启用 Discord 内的斜杠 / 右键菜单命令。
|
||||
消息通过 Discord **REST API** 发送,因此仅凭 `DISCORD_TOKEN` 即可推送。交互(斜杠命令、按钮、modal)则通过 HTTPS Interactions Endpoint 送达:
|
||||
|
||||
- `DISCORD_GATEWAY_ENABLED=false`(默认):仅 REST,不建立 Gateway 连接。
|
||||
- `DISCORD_GATEWAY_ENABLED=true`:由一个 Durable Object 持有 Gateway 连接,并按服务器注册 `/gh` 斜杠命令以及 `GitHub: 添加/编辑/删除评论` 消息命令。
|
||||
1. 在 Discord 开发者门户 → General Information 复制应用的 **Public Key**,填入 `DISCORD_PUBLIC_KEY`。
|
||||
2. 将 **Interactions Endpoint URL** 设为 `https://your-domain/discord/interactions`。
|
||||
3. 所有交互请求都使用 Ed25519 签名验证(`X-Signature-Ed25519` 覆盖 `X-Signature-Timestamp + body`)。
|
||||
|
||||
启用后,用户运行 `/gh login` 绑定自己的 GitHub 账号,即可以本人身份评论 issue/PR。完整命令说明见 [README](https://github.com/ReCloudStudio/WebHooker#bot-commands-comment-on-github-as-yourself)。
|
||||
`/gh` 斜杠命令与 `GitHub: 添加/编辑/删除评论` 消息命令由定时任务(每 5 分钟)同步注册:按服务器即时可用,同时全局注册(24h 去重,约 1 小时传播)。Bot 从不连接 Discord Gateway,因此显示为**离线**——消息推送不受影响(始终走 REST)。
|
||||
|
||||
用户运行 `/gh login` 绑定自己的 GitHub 账号,即可以本人身份评论 issue/PR。完整命令说明见 [README](https://github.com/ReCloudStudio/WebHooker#bot-commands-comment-on-github-as-yourself)。
|
||||
|
||||
## 自定义域名(可选)
|
||||
|
||||
|
|
@ -132,4 +136,4 @@ docker build -t webhooker .
|
|||
docker run -p 8787:8787 --env-file .env webhooker
|
||||
```
|
||||
|
||||
注意:Docker 模式下不包含 Durable Objects 和 KV。完整功能请使用 Cloudflare 部署。
|
||||
注意:Docker 模式下不包含 KV 等 Cloudflare 存储。完整功能请使用 Cloudflare 部署。
|
||||
|
|
|
|||
|
|
@ -34,12 +34,13 @@ 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
|
||||
DISCORD_PUBLIC_KEY=your-public-key
|
||||
ADMIN_USER_IDS=your-github-id,your-github-login
|
||||
BASE_URL=http://localhost:8787
|
||||
```
|
||||
|
||||
::: tip
|
||||
`GITHUB_PRIVATE_KEY` 必须是 **PKCS#8** 格式(`BEGIN PRIVATE KEY`)。用 `openssl pkcs8 -topk8 -nocrypt -in app.pem -out pkcs8.pem` 转换 GitHub 下发的 PKCS#1 私钥。目标频道在 Web UI 中按路由设置,因此不需要 `DISCORD_CHANNEL_ID`。若要让 Bot 保持在线并在本地启用 `/gh` 斜杠命令,可额外设置 `DISCORD_GATEWAY_ENABLED=true`。
|
||||
`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`。
|
||||
:::
|
||||
|
||||
::: warning
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# 简介
|
||||
|
||||
WebHooker 是一个基于 Cloudflare Workers 构建的 GitHub webhook 调度器。它接收 GitHub webhook 事件,应用可配置的过滤器,将事件格式化为丰富的 Discord 嵌入消息,并通过 Discord REST API 投递到 Discord 频道或帖子。一个可选的 Durable Object 持有 Gateway 连接,用于让 Bot 保持在线并支持 Discord 内的 `/gh` 命令。路由通过内置的 Web UI 管理。
|
||||
WebHooker 是一个基于 Cloudflare Workers 构建的 GitHub webhook 调度器。它接收 GitHub webhook 事件,应用可配置的过滤器,将事件格式化为丰富的 Discord 嵌入消息,并通过 Discord REST API 投递到 Discord 频道或帖子。Discord 内的 `/gh` 交互通过 HTTPS Interactions Endpoint(Ed25519 验签)送达。路由通过内置的 Web UI 管理。
|
||||
|
||||
## 架构
|
||||
|
||||
|
|
@ -12,7 +12,7 @@ GitHub Webhook → Cloudflare Worker (Hono)
|
|||
├── /admin → 路由与发送日志 Web UI(管理员会话)
|
||||
└── GET /health → 健康检查
|
||||
|
||||
(可选)Durable Object ⇄ Discord Gateway → Bot 在线 + /gh 斜杠与右键命令
|
||||
POST /discord/interactions → 验证 (Ed25519) → 处理 /gh 斜杠与右键命令
|
||||
```
|
||||
|
||||
### 组件
|
||||
|
|
@ -20,7 +20,7 @@ GitHub Webhook → Cloudflare Worker (Hono)
|
|||
| 组件 | 职责 |
|
||||
| ----------------------------------- | --------------------------------------------------------------------------------------------------------- |
|
||||
| **Cloudflare Worker** | HTTP 入口、签名验证、投递去重、事件解析、路由匹配、REST 发送 |
|
||||
| **Durable Object (DiscordGateway)** | _可选。_ 保持 Gateway 连接(Bot 在线)并处理 `/gh` 交互 |
|
||||
| **Interactions Endpoint** | 验证 Ed25519 签名并处理 `/gh` 交互(斜杠命令、右键菜单、按钮、modal) |
|
||||
| **KV** | Token 存储 (`token:{userId}`)、OAuth 状态 (`state:{hex}`)、路由配置 (`config:routes`)、发送日志、投递去重 |
|
||||
|
||||
### 数据流
|
||||
|
|
@ -37,7 +37,7 @@ GitHub Webhook → Cloudflare Worker (Hono)
|
|||
|
||||
- **运行时**: Cloudflare Workers
|
||||
- **HTTP 框架**: Hono
|
||||
- **Discord 投递**: Discord REST API(Gateway 通过可选的 Durable Object 提供在线状态与 `/gh` 命令)
|
||||
- **Discord 投递**: Discord REST API(交互通过 Ed25519 验签的 HTTPS Interactions Endpoint)
|
||||
- **Web UI**: Nuxt 3 静态 SPA,由 Worker 资源托管
|
||||
- **存储**: Cloudflare KV
|
||||
- **鉴权**: Web Crypto API (HMAC-SHA256)、jose (JWT)、octokit (GitHub API)
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@ features:
|
|||
- title: 灵活的过滤器
|
||||
details: 支持按事件类型、仓库、参与者、操作、分支(含 PR)和关键字(支持正则)过滤。支持排除模式。
|
||||
- title: Cloudflare Workers
|
||||
details: 运行在 Cloudflare 边缘网络上。通过 Discord REST API 发送消息,并可选地用 Durable Object 维持 Gateway 连接以提供在线状态与斜杠命令。
|
||||
details: 运行在 Cloudflare 边缘网络上。通过 Discord REST API 发送消息,并通过 Ed25519 验签的 Interactions Endpoint 支持 `/gh` 命令。
|
||||
- title: Web UI 与斜杠命令
|
||||
details: "在内置管理控制台中管理路由、查看发送日志。绑定你的 GitHub 账号,通过 /gh 命令以本人身份评论 issue/PR。"
|
||||
- title: 签名验证
|
||||
details: 使用 Web Crypto API 进行 HMAC-SHA256 webhook 签名验证,支持时间安全比较。
|
||||
details: 使用 Web Crypto API 进行 HMAC-SHA256 webhook 签名验证与 Ed25519 交互签名验证,支持时间安全比较。
|
||||
- title: 优雅降级
|
||||
details: 当 Discord Token 不可用时以 webhook-only 模式运行。提供健康检查端点用于监控。
|
||||
---
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue