makecindy / makecindy/cindy

[Bug] 禁止同一 Discord Bot 同时绑定多个 Cindy 账号

Open
#187 3 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
TypeScript
Stars
2.7k
Forks
395
Avg merge
21h 48m
Merged PRs (30d)
776

Description

## 问题描述

当前同一个 Discord Bot 可以在多台机器上的不同 Cindy 客户端中重复绑定。

当两台机器使用相同的 Discord Bot Token,并且配置了相同的 Discord User ID 时,两个不同的 Cindy 账号都可以显示为已连接。例如:

```text
同一个 Discord Bot
└── Discord User ID: 978995447966343238
├── Cindy 账号 A / 机器 A
└── Cindy 账号 B / 机器 B
```

这会导致同一个 Discord 私聊消息同时被多个 Cindy 客户端认为属于自己,无法确定应该由哪个 Cindy 处理。

## 当前行为

每个 Cindy 客户端在本地保存 Discord Bot Token 和 Owner User ID,并独立建立 Discord Gateway 连接。收到 Discord 私聊消息后,客户端只根据本地配置的 Owner User ID 判断是否接收消息。由于绑定状态没有在服务端进行全局唯一性校验,因此:

- 同一个 Bot 可以被多个 Cindy 账号重复绑定;
- 相同 User ID 的消息可能同时到达多个客户端;
- 多个 Cindy 可能同时回复同一条 Discord 消息;
- 用户无法知道当前 Discord Bot 实际归属于哪个 Cindy;
- 在一个客户端解绑或重新绑定时,其他客户端不会同步感知。

相关代码:

- `packages/lizi-im/src/discord/index.ts`
- `packages/lizi-im/src/discord/gateway.ts`
- `apps/desktop/src/main/im/host.ts`
- `apps/desktop/src/renderer/components/settings/DiscordBotSection.tsx`
- `apps/desktop/src/preload/preload.ts`

## 期望行为

同一个 Discord Bot 应该只能绑定到一个 Cindy 账号/客户端。

当其他 Cindy 账号尝试绑定已经被占用的 Discord Bot 时:

1. 服务端拒绝新的绑定;
2. 当前客户端显示明确的错误提示,例如“该 Discord Bot 已绑定到其他 Cindy 账号”;
3. 已经生效的原绑定不受影响;
4. 用户需要先在原 Cindy 账号中解绑,新的 Cindy 才可以重新绑定。

建议以 Discord Bot 的唯一身份作为冲突判断依据,例如 Discord Bot Application ID。不建议只使用 Bot Token 作为业务层唯一键,因为 Token 属于敏感凭证,应避免作为普通绑定记录或错误信息的一部分。

## 验收标准

- [ ] 同一个 Discord Bot 只能存在一个有效的 Cindy 绑定;
- [ ] 不同 Cindy 账号尝试绑定同一个 Bot 时,后绑定操作被拒绝;
- [ ] 拒绝时显示可理解的错误信息;
- [ ] 后绑定失败不会覆盖或断开原有绑定;
- [ ] 原绑定客户端继续正常接收和处理 Discord 消息;
- [ ] 原绑定客户端解绑后,其他 Cindy 才可以重新绑定该 Bot;
- [ ] 应用重启和网络重连不会绕过唯一性校验;
- [ ] 两台不同机器、两个不同 Cindy 账号使用相同 Bot Token 和相同 User ID 的场景有回归测试;
- [ ] 同一 Cindy 账号在多台机器重复运行时,也需要明确处理,不能产生多个并行消费者;
- [ ] Bot Token 继续使用安全存储,不以明文写入数据库、日志或错误提示。

## 需要考虑的实现问题

当前 Discord 配置主要保存在本机安全存储中,本地 `im_bindings` 表无法承担跨 Cindy 账号的全局唯一校验。因此需要在服务端或统一的账户绑定服务中增加 Discord Bot 绑定登记,至少记录:

- Discord Bot Application ID;
- 当前绑定的 Cindy 账号;
- 绑定设备或客户端信息;
- 绑定时间;
- 绑定状态;
- 解绑/接管所需的授权信息。

绑定和解绑操作必须是原子的,避免两个 Cindy 客户端同时发起绑定时都通过检查。

## 边界说明

本 Issue 讨论的是同一个 Discord Bot 被多个 Cindy 账号绑定的情况,不论这些账号配置的是相同还是不同的 Discord User ID。原则上都应该禁止,因为消息消费权属于 Bot 连接,而不是简单属于某个 Owner User ID。

一个 Cindy 账号配置多个不同 Discord Bot 是否支持,属于另一个独立需求。

Contributor guide

Open the contributing guide

Research direction

Trace the existing binding flow through packages/lizi-im/src/discord/index.ts, packages/lizi-im/src/discord/gateway.ts, apps/desktop/src/main/im/host.ts, apps/desktop/src/renderer/components/settings/DiscordBotSection.tsx, and apps/desktop/src/preload/preload.ts. First identify where binding requests and errors cross the client boundary, then locate the service-side binding entry point, which is not named here. Done means concurrent duplicate bindings are rejected without affecting the original, unbinding permits rebinding, and the listed restart, reconnection, and multi-machine cases are covered by regression tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
electron, typescript
Domain
backend-api-design, desktop
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.