0.1.13 • Published yesterday
koishi-plugin-super-event-message-push
Licence
MIT
Version
0.1.13
Deps
0
Size
13 kB
Vulns
0
Weekly
0
koishi-plugin-super-event-message-push
用于接收后端推送的消息并通过 OneBot 协议转发到 QQ 群的 Koishi 插件。
功能
- 接收来自后端的 webhook 请求
- 使用 HMAC-SHA256 + 时间戳验证请求签名
- 通过 OneBot 协议将消息转发到指定 QQ 群
- 防重放攻击(5 秒时间窗口)
配置
插件配置
在 Koishi 控制台中配置以下参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
endpoint |
string | /super-event/webhook |
接收 webhook 的路径 |
secret |
string | change-me |
用于验证签名的密钥(需与后端配置一致) |
apiBaseUrl |
string | http://localhost:4000/api |
后端 API 地址(保留用于未来功能) |
依赖
需要安装以下插件:
@koishijs/plugin-server- HTTP 服务器支持@koishijs/plugin-adapter-onebot- OneBot 协议适配器
使用方法
1. 配置后端
在后端的 .env 文件中配置:
KOISHI_WEBHOOK_URL=http://your-koishi-server:5140/super-event/webhook
KOISHI_WEBHOOK_SECRET=your-secret-key
2. 后端调用示例
方式一:通过公共 Webhook 接口(推荐)
import crypto from 'crypto';
import axios from 'axios';
/**
* 推送消息到 Koishi
*/
async function pushToKoishi(channel: number, message: string) {
const secret = process.env.KOISHI_WEBHOOK_SECRET || 'change-me';
const url = 'http://localhost:4000/api/push/webhook';
const body = JSON.stringify({ channel, message });
const timestamp = Math.floor(Date.now() / 1000);
const signature = crypto
.createHmac('sha256', secret)
.update(timestamp + body)
.digest('hex');
const response = await axios.post(url, { channel, message }, {
headers: {
'x-super-event-signature': signature,
'x-super-event-timestamp': String(timestamp),
'content-type': 'application/json',
},
});
return response.data;
}
// 使用示例
await pushToKoishi(123456789, '这是一条测试消息');
方式二:直接调用后端服务(需要权限)
import axios from 'axios';
async function pushToKoishiWithAuth(channel: number, message: string, token: string) {
const response = await axios.post(
'http://localhost:4000/api/push',
{ channel, message },
{
headers: {
'Authorization': `Bearer ${token}`,
'content-type': 'application/json',
},
}
);
return response.data;
}
3. 前端调用示例
import crypto from 'crypto-js';
/**
* 前端推送消息到 Koishi(通过后端中转)
*/
async function sendMessageToGroup(channel: number, message: string) {
const secret = 'your-secret-key'; // 注意:实际项目中不要在前端硬编码密钥
const body = JSON.stringify({ channel, message });
const timestamp = Math.floor(Date.now() / 1000);
// 使用 crypto-js 计算签名
const signature = crypto.HmacSHA256(timestamp + body, secret).toString();
const response = await fetch('http://localhost:4000/api/push/webhook', {
method: 'POST',
headers: {
'x-super-event-signature': signature,
'x-super-event-timestamp': String(timestamp),
'content-type': 'application/json',
},
body,
});
return response.json();
}
API 规范
请求格式
URL: POST {koishi-url}{endpoint}
Headers:
x-super-event-signature: HMAC-SHA256(secret, timestamp + body)x-super-event-timestamp: Unix 时间戳(秒)content-type: application/json
Body:
{
"channel": 123456789,
"message": "要发送的消息内容"
}
响应格式
成功响应 (200)
{
"success": true,
"message": "Message sent successfully"
}
错误响应
- 400 Bad Request: 缺少签名/时间戳,或请求体格式错误
{
"error": "Missing signature or timestamp"
}
- 401 Unauthorized: 签名验证失败
{
"error": "Invalid signature"
}
- 404 Not Found: 请求已过期(超过 5 秒)
{
"error": "Request expired"
}
- 500 Internal Server Error: 发送消息失败或没有可用的 OneBot 适配器
{
"error": "Failed to send message",
"details": "错误详情"
}
安全性
签名验证
使用 HMAC-SHA256 算法生成签名,确保消息来自可信来源:
signature = HMAC_SHA256(secret, timestamp + body)
防重放攻击
- 每个请求必须包含时间戳
- 服务器只接受 5 秒内的请求
- 超过时间窗口的请求返回 404
最佳实践
- 使用强密钥:
KOISHI_WEBHOOK_SECRET应使用随机生成的强密钥 - HTTPS 传输: 生产环境中使用 HTTPS 保护传输过程
- 密钥管理: 不要在前端代码中硬编码密钥,通过后端中转
- 访问控制: 配置防火墙规则,限制只有后端服务器可以访问 Koishi webhook
故障排查
消息发送失败
- 检查 OneBot 适配器是否已启动并连接
- 查看 Koishi 日志确认是否收到请求
- 确认群号是否正确,机器人是否在该群内
签名验证失败
- 确认后端和 Koishi 的
secret配置一致 - 检查时间戳是否在 5 秒内
- 确认请求体格式是否正确(JSON 字符串)
请求过期
- 检查服务器时间是否同步(使用 NTP)
- 网络延迟过大时适当调整时间窗口
开发
构建
pnpm install
pnpm build
测试
pnpm test
许可证
MIT