feat(channel): KOOK Webhook(WH) 接收模式——与 WS 配置切换(ReceiveMode)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

- kook.Config 加 ReceiveMode("ws"默认/"webhook") + WebhookPath(默认/webhook/kook) + WebhookVerifyToken + WebhookEncryptKey(AES-256-CBC)
- 按权威文档(Reference/kaiheila webhook.md)实现: 无X-Signature HMAC, 真实校验=d.verify_token比对(不匹配403)+可选AES解密+zlib解压+challenge回显
- webhook.go: InboundHandler+WebhookPath, POST→zlib解压→AES解密→verify_token校验→challenge回显→归一UnifiedMessage→SetMessageHandler; WS模式Connect不拨网关仅标记connected
- channelbridge/webhookAdapter 接口改用 WebhookPath(); WebhookHandlers 收KOOK WH(ws模式跳过); 既有webhook通道补WebhookPath照常挂载
- namedAdapter 转发InboundHandler/WebhookPath; kook env兜底 +4个CHANNEL_KOOK_*键
- 测试: verify_token 403/challenge/zlib/AES往返/WebhookPath按模式/WH不拨gateway/WebhookHandlers收KOOK; 全仓build/vet/test绿
- 待真token端到端实测(需主人提供CHANNEL_KOOK_TOKEN+开发者后台切WebHook配回调URL)
This commit is contained in:
Aska committed 2026-09-07 14:10:03 +08:00
1 parent 1ebc82fffd
commit 617157262b
11 files changed
+981 -32

No files matched your search

@@ -31,15 +31,16 @@ import (
)
// webhookAdapter is the optional capability a channel adapter may expose to
// source an HTTP inbound callback. *webhook.Adapter implements it via
// InboundHandler(). The bridge reports these so the gateway can mount them.
// source an HTTP inbound callback. *webhook.Adapter and *kook.Adapter (webhook
// mode) implement it. The bridge reports these so the gateway can mount them.
type webhookAdapter interface {
// InboundHandler returns the http.Handler the gateway mounts at the adapter's
// configured endpoint path to receive external callbacks.
// InboundHandler returns the http.Handler the gateway mounts at the route to
// receive external callbacks.
InboundHandler() http.Handler
// Config returns the adapter config snapshot; the endpoint path is read from
// it so the gateway can register the correct route.
Config() map[string]any
// WebhookPath returns the route the gateway should mount the handler at. It
// returns "" when the adapter is not currently exposing a webhook, letting the
// bridge skip it (e.g. a websocket-mode KOOK).
WebhookPath() string
}
// Knob constants. Compile-time so no bare magic number appears in the run path
@@ -229,12 +230,17 @@ func (b *Bridge) WebhookHandlers() map[string]http.Handler {
if !ok {
continue
}
cfg := wh.Config()
path, _ := cfg["endpointPath"].(string)
path := wh.WebhookPath()
if path == "" {
path = "/webhook"
// Adapter is not currently exposing a webhook (e.g. a websocket-mode
// KOOK); skipping avoids mounting a handler at a stale or colliding route.
continue
}
out[path] = wh.InboundHandler()
h := wh.InboundHandler()
if h == nil {
continue
}
out[path] = h
}
if len(out) == 0 {
return nil