Skip to content

fix(qq): harden onebot access control - #66

Open
kilockok wants to merge 1 commit into
mainfrom
codex/qq-onebot-access-control
Open

fix(qq): harden onebot access control#66
kilockok wants to merge 1 commit into
mainfrom
codex/qq-onebot-access-control

Conversation

@kilockok

@kilockok kilockok commented May 16, 2026

Copy link
Copy Markdown
Collaborator

Summary:

  • normalize QQ OneBot allowlists and reject stale allow_all_users
  • reply to denied QQ messages only when the message triggered the bot
  • persist QQ OneBot access list changes from desktop settings
  • resolve managed NapCat endpoints for the OneBot WS listener

Tests:

  • go test -count=1 ./internal/http/accountapi
  • go test -tags desktop ./internal/http/accountapi -run 'TestQQ|TestResolveQQ' -count=1
  • pnpm --dir src/apps/web test -- desktopChannelsSettings.test.tsx
  • git diff --check origin/main...HEAD

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: de02b7d108

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +306 to +311
if !qqUserAllowed(cfg, userID, groupID) {
if qqShouldReplyAccessDenied(incoming) {
msgType, target := qqAccessDeniedReplyDestination(userID, groupID)
c.sendQQReply(ctx, cfg, msgType, target, qqAccessDeniedReplyText)
}
return nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reinstate QQ private-link gate before accepting traffic

This new allowlist-only gate lets unbound users through whenever allow_all_users is true (the default when no allowlists are set), because private QQ messages now proceed without any channel_identity_links check. In that state, any QQ user who can DM the bot can execute commands like /new and create runs on the channel, which is a security regression from the previous bootstrap-then-bind behavior.

Useful? React with 👍 / 👎.

Comment thread src/services/api/internal/http/accountapi/channels_qq_ws.go
@kilockok
kilockok force-pushed the codex/qq-onebot-access-control branch from de02b7d to 66a5b30 Compare May 16, 2026 09:00
@qqqqqf-q
qqqqqf-q changed the base branch from codex/ui-surfaces-atomic to main May 16, 2026 09:00
@qqqqqf-q

Copy link
Copy Markdown
Owner

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 66a5b3060a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +306 to +311
if !qqUserAllowed(cfg, userID, groupID) {
if qqShouldReplyAccessDenied(incoming) {
msgType, target := qqAccessDeniedReplyDestination(userID, groupID)
c.sendQQReply(ctx, cfg, msgType, target, qqAccessDeniedReplyText)
}
return nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Record denied QQ events before sending denial replies

This branch sends qqAccessDeniedReplyText and returns before the inbound ledger/receipt deduplication logic runs, so a retried/replayed OneBot event with the same message ID will emit the denial reply again. In practice, disallowed users can receive duplicate denial messages whenever delivery is retried (for example after reconnects), because the message is never recorded as processed on the denial path.

Useful? React with 👍 / 👎.

setAllowedUserIDs(nextIDs)
setAllowedUserInput('')
setSaved(false)
await persistQQSettings(nextIDs, mergeListValues(allowedGroupIDs, allowedGroupInput))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid persisting draft IDs from the other access list

When adding an allowed QQ user, this call also persists mergeListValues(allowedGroupIDs, allowedGroupInput), which includes whatever is currently typed in the group input even if the user never clicked “add” for groups. That means partial or unintended group IDs can be silently committed just by adding a user (and the symmetric path does the same in reverse), causing unexpected access-control changes.

Useful? React with 👍 / 👎.

@qqqqqf-q qqqqqf-q left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不合。核心问题:自搓权限轮子。

阻塞

私聊 bind 访问控制被移除,替换为自建的 allowlist 权限体系

原有的 telegramLinkBootstrapAllowed + HasLink 检查被完整删除,替换为基于 QQ 号的 allowlist 分级。这是一套独立于现有 bind 体系的新权限模型,没有提前沟通就上了。

现有的 channel binding 体系已经提供了身份关联和权限控制的基础设施,应该在此基础上扩展,而不是另起炉灶。qqChannelIdentityIsOwnerqqShouldReplyAccessDenied 这些函数的存在本身就说明在绕过现有架构。

要求

  1. 不要自建权限模型,复用现有的 bind 访问控制体系
  2. 如果现有体系不满足 QQ 场景的需求,先讨论方案再动手

非阻塞(代码质量本身没问题的部分)

以下改动如果从权限重构中拆出来,可以单独提 PR:

  • allowlist 归一化(去重、trim、多分隔符支持)— 这个有价值
  • NapCat WS endpoint 自动解析 — 独立功能,可以单独合
  • 前端 add/remove 立即持久化 — UX 改进,可以单独合

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants