fix(channel,user): owner 车道只认白名单,堵住群主/伪造 role 冒充主人(裁决 06.4.2/06.4.3/06.4.4)
- 适配器只描述平台身份:qq_obv11 的 owner/admin 一律上报 RoleMember,不再上报 RoleOwner - session 层唯一判主点只认白名单(owner.yaml Accounts ∪ 每渠道 adminIds),nil 档案 fail-closed 拒绝 - 新增「每渠道管理员层」:channels.json ChannelAccount.adminIds[] → runtimeconfig.AdminIDs → OwnerProfile.SetPlatformAdmins(整体替换语义,热重载后移除的 id 立即失效) - 组合根接线:启动即播种、面板保存先灌白名单再重载适配器(cmd/cyrene/wire_channels.go + 4 条端到端单测) - 06.4.3 节流与参与度状态按会话独立计数(ConversationKey 三处统一,空会话 GC);06.4.4 未知平台主动发言保守默认 1 条/分钟
This commit is contained in:
1 parent
7e7f53bb41
commit
af8591b78a
30 files changed
+1289
-144
No files matched your search
@@ -50,6 +50,12 @@ func (r *ownerRegistrar) RegisterChannelOwner(_ context.Context, platform, accou
|
||||
return nil
|
||||
}
|
||||
|
||||
// LiveOwnerProfile 是 ownerRegistrar 对 gateway.liveOwnerProfile 可选扩展的实现(裁决
|
||||
// 10.4.5):管理面板 PUT /admin/owner-profile 保存后,gateway 需要拿到**同一个**活档案指针
|
||||
// 做热替换——渠道 bridge 判定 actor 用的就是这个指针,所以热替换无需重启即生效。启动时档案
|
||||
// 加载失败则为 nil,gateway 会退回「真实落盘 + 提示需重启」,绝不假装热生效。
|
||||
func (r *ownerRegistrar) LiveOwnerProfile() *user.OwnerProfile { return r.owner }
|
||||
|
||||
// wireChannels constructs the four IM channel adapters from environment
|
||||
// configuration, registers them so the admin API can enumerate them, and wires
|
||||
// them into the channel bridge so a configured adapter connects and routes
|
||||
@@ -112,7 +118,19 @@ func (a *app) wireChannels() error {
|
||||
}
|
||||
bridge.Start()
|
||||
a.channelBridge = bridge
|
||||
a.channels = &runtimeChannels{path: channelsPath, fallback: factory.fallback, bridge: bridge, log: a.log}
|
||||
// 保留具体类型:gateway 只看到 ChannelConfigStore 接口,而启动播种管理员白名单
|
||||
// 需要 concrete runtimeChannels 的方法。
|
||||
rc := &runtimeChannels{
|
||||
path: channelsPath,
|
||||
fallback: factory.fallback,
|
||||
bridge: bridge,
|
||||
owner: a.owner,
|
||||
log: a.log,
|
||||
}
|
||||
// 启动即灌一次每渠道管理员白名单(裁决 06.4.2):不必等面板打开或热重载,
|
||||
// channels.json 里声明的 adminIds 从第一帧入站消息起就参与判主。
|
||||
rc.applyAdminIDs(rc.loadAccounts())
|
||||
a.channels = rc
|
||||
a.log.Info("channel adapters registered", "count", len(adapters))
|
||||
return nil
|
||||
}
|
||||
@@ -125,12 +143,22 @@ type runtimeChannels struct {
|
||||
path string
|
||||
fallback map[string][]config.ChannelAccount
|
||||
bridge *channelbridge.Bridge
|
||||
log *slog.Logger
|
||||
// owner 是渠道 bridge 判 actor 用的**同一个**活档案指针:读配置时把每渠道管理员
|
||||
// 白名单灌进它的 adminIDs 层(裁决 06.4.2),面板保存后无需重启即生效。
|
||||
owner *user.OwnerProfile
|
||||
log *slog.Logger
|
||||
}
|
||||
|
||||
func (r *runtimeChannels) Path() string { return r.path }
|
||||
|
||||
func (r *runtimeChannels) Load() map[string][]config.ChannelAccount {
|
||||
accounts := r.loadAccounts()
|
||||
r.applyAdminIDs(accounts)
|
||||
return accounts
|
||||
}
|
||||
|
||||
// loadAccounts 只负责「读配置」:文件优先、env 兜底(design/04 §3.1)。
|
||||
func (r *runtimeChannels) loadAccounts() map[string][]config.ChannelAccount {
|
||||
accounts, warn := runtimeconfig.LoadChannels(r.path, r.fallback)
|
||||
if warn != nil {
|
||||
r.log.Warn("channels.json load fell back to env", "error", warn)
|
||||
@@ -138,7 +166,22 @@ func (r *runtimeChannels) Load() map[string][]config.ChannelAccount {
|
||||
return accounts
|
||||
}
|
||||
|
||||
func (r *runtimeChannels) Reload(platform string) error { return r.bridge.Reload(platform) }
|
||||
// applyAdminIDs 把各平台声明的 adminIds 整体替换进活主人档案(裁决 06.4.2)。整体替换
|
||||
// 语义保证热重载后已删除的管理员 id 立即失效;owner.yaml 的账号白名单不受影响。
|
||||
func (r *runtimeChannels) applyAdminIDs(accounts map[string][]config.ChannelAccount) {
|
||||
if r.owner == nil {
|
||||
return
|
||||
}
|
||||
for platform, ids := range runtimeconfig.AdminIDs(accounts) {
|
||||
r.owner.SetPlatformAdmins(platform, ids)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *runtimeChannels) Reload(platform string) error {
|
||||
// 先灌管理员白名单再重载适配器:面板一次保存(adminIds + 凭据)两条路径同时生效。
|
||||
r.applyAdminIDs(r.loadAccounts())
|
||||
return r.bridge.Reload(platform)
|
||||
}
|
||||
|
||||
// reviewFor builds the channel-bridge review model (design/12 §6 策略四), or nil
|
||||
// when no model adapter is available so the gate falls back to FIFO eviction — the
|
||||
|
||||
Reference in new issue
Block a user