feat(channels): 适配器入站内联附件字节(telegram/kook/qq_obv11/weixin_ilink)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

- 新增 internal/channel/mediafetch:来源白名单(deny-by-default,支持 *.suffix)
  + 逐跳重定向校验 + 边读边限 + 超时;只回来源主机,绝不回完整 URL
- 四渠道各自 media.go 接通入站内联:只从平台载荷给出的引用取回字节
  (telegram file_id→getFile→file_path 形态校验;kook CDN;qq 文件段 url;
   weixin cdnURL + AES-ECB 解密)
- 常量全部复用既有来源:documents.ExtAllowed / DefaultMaxBytes / MaxPerMessage
- channelbridge 诚实提示文案改为对「渠道只给远程引用」与「代取失败」两种成因都成立
- 18 个测试函数(含四渠道「正文里的 URL ⇒ 0 次命中」红线反证、端到端进模型可见视图)
- 变异验证:去掉尺寸上限 ⇒ 四渠道红(含修正后不再是假绿的 weixin 超量用例)
This commit is contained in:
AskaEth committed 2026-10-04 22:13:17 +08:00
1 parent 46caa724f2
commit 3be70f8232
22 files changed
+2601 -19

No files matched your search

+52
View File
@@ -0,0 +1,52 @@
package kook
// 本文件承载 KOOK 的**入站附件字节内联**(切片 IM-1):KOOK 的 s=0 消息把附件地址
// 直接放在 `content` 字段里(图片/视频/文件/音频同理),因此文件类消息拿到的是一个
// 绝对 CDN 地址,可以按来源白名单直接取回。
//
// 两条边界:
// - **只认平台资产主机**:白名单 = KOOK 附件 CDN(`img.kookapp.cn`)+ 已配置的
// API 根(`base_url`)。`content` 字段是发送方可影响的内容(一个伪造的文件消息
// 完全可以填任意字符串),因此**不是**「平台保证的地址」——白名单在这里是硬门:
// 不在白名单里,一个字节都不发出去;
// - 尺寸/超时/预筛/日志口径全在 `internal/channel/mediafetch`(四个适配器共用)。
import (
"context"
"git.yeij.top/AskaEth/Cyrene_v2/internal/channel/adapter"
"git.yeij.top/AskaEth/Cyrene_v2/internal/channel/mediafetch"
)
// kookAssetOrigin 是 KOOK 附件的 CDN 来源(平台只在它上面提供附件地址)。
const kookAssetOrigin = "https://img.kookapp.cn"
// inlineInboundMedia 把受支持格式的文件附件取回并内联到消息上。失败不抛出:该附件
// 保持无字节,由 channelbridge 的入站摄取照既有口径给模型一行诚实提示。
func (a *Adapter) inlineInboundMedia(ctx context.Context, msg *adapter.UnifiedMessage) {
mediafetch.Inline(ctx, a.log, msg, kookFetcher{a: a})
}
// kookFetcher 实现 mediafetch.Fetcher:KOOK 的媒体引用就是 `content` 里的绝对地址。
type kookFetcher struct{ a *Adapter }
// Fetch 按来源白名单取回一份 KOOK 附件。
func (f kookFetcher) Fetch(ctx context.Context, m adapter.Media) ([]byte, error) {
return mediafetch.Fetch(ctx, mediafetch.Request{
URL: m.URL,
Allow: f.a.assetAllowlist(),
Client: f.a.client,
Timeout: mediafetch.DefaultTimeout,
})
}
// assetAllowlist 给出 KOOK 附件的来源白名单:附件 CDN + 已配置的 API 根。第二条是
// 为了让**自建/私有化部署**(把 `base_url` 指到自己的网关)也能走通,且它的可信度与
// 其余 API 调用一致(同一条由部署声明的地址)。两条都读不出来时给空名单 ⇒ 谁都不许。
func (a *Adapter) assetAllowlist() mediafetch.Allowlist {
origins := []string{kookAssetOrigin}
if origin, err := mediafetch.OriginOf(a.baseURL); err == nil {
origins = append(origins, origin)
}
return mediafetch.NewAllowlist(origins...)
}