Skip to content

[Bug][严重] v0.6.0 重置券消费 RPC 超时自动重放,一次确认可能重复扣券(本地复现 1→4 请求) #472

Description

@DongCunHui1108

版本

v0.6.0(Windows 桌面端;源码标签 v0.6.0 / 964e11a

影响范围

Desktop

环境信息

Windows,CodexManager 0.6.0 桌面安装版。涉及 Desktop → 本地 Service 的 RPC 传输及重置券消费处理。

源码核对和独立 Rust 本地假服务验证由 Codex 协助完成。未对安装二进制做可复现构建比对;未声称其他版本均受影响。

复现步骤

用户侧现象

只确认一次“重置 5h + 7d”,观察到可用重置券减少两张。没有为了调查再次触发真实重置。

安全的本地复现(不要用真实重置券测试)

  1. 将 v0.6.0 的 apps/src-tauri/src/rpc_client/transport.rs 和 http.rs 原样放入独立 Rust 测试程序;外围 RPC 类型和鉴权函数使用测试桩。
  2. 假服务仅监听 127.0.0.1 和 ::1 的随机端口,读取完整 HTTP 请求后计数,等待 12 秒才返回成功响应。无真实账号、无真实凭据、无上游连接。
  3. 只调用一次原始 rpc_call_with_sockets,method 为 account/usage/resetCredit/consume,传入两个本地 socket 地址及虚构 accountId。
  4. 观察假服务接收次数。

实测:一次客户端调用 → 四次消费 RPC 到达假服务,耗时约 40.2 秒,客户端最终返回错误;assert_eq!(received, 4) 与 assert!(result.is_err()) 均通过,退出码 0。该测试验证重复发请求,不模拟真实上游扣券。

预期结果

一次用户确认最多消费一张重置券。请求可能已经发送但响应超时/丢失时,不应把整个非幂等操作当作新交易重放;应返回“结果未知”,查询并核对结果。即使发生传输重试,同一次操作也必须使用稳定幂等标识,后端去重。

实际结果

严重性与证据边界

用户观察到一次确认减少两张券;本地测试已独立确认一次 RPC 被重发四次。真实上游逐张兑换流水尚未取得,不能将四次 RPC 等同于四张券被成功消费,也尚未逐笔证明本次哪两次请求成功。

源码定位(固定提交,便于复核)

  • transport.rs:默认 IO 超时 10 秒;重置消费没有专用超时。
  • 同文件 L129 起:write_all 已完成后,read_to_string 超时也返回普通 Err。
  • 同文件 L198–208:for attempt in 0..=1,再遍历所有 socket;读超时后仍重新发送整个 RPC。双地址时最多四次。
  • usage_reset_credits.rs L242–269:账号 Mutex 只让请求排队;每次调用在 L254 新建 redeem_request_id,没有跨 RPC 的操作去重。上游 HTTP 重试复用单次调用内的 ID,无法覆盖桌面层重新调用。
  • 扣券成功后还同步刷新 usage、读取券快照才返回 RPC;这些后续查询慢,也可能令已完成的扣券被桌面误当成超时并重发。

建议优先修复

  1. 非幂等 RPC 一旦可能已发送,禁止基于读超时、空响应或解析失败自动重放。
  2. 一次确认生成稳定 operationId,跨重试复用;后端持久化去重,并关联稳定的 redeem_request_id。
  3. 扣券成功响应与后续用量刷新解耦;延长超时只能缓解,不能替代幂等。
  4. 增加延迟响应、响应丢失、IPv4/IPv6 回退、同一 operationId 重复提交的假服务回归测试。
  5. 修复发布前建议提醒用户暂停使用该按钮,尤其不要在报错后再次确认。

请维护者优先确认并评估严重级别;这会消耗用户有限的重置券,并非单纯显示错误。

脱敏日志 / 截图

不上传原始应用日志或账号截图,避免泄露凭据和账号资料。以下仅为无真实账号的本地假服务测试输出:

FAKE_SERVER received consumption RPC #1
FAKE_SERVER received consumption RPC #2
FAKE_SERVER received consumption RPC #3
FAKE_SERVER received consumption RPC #4
RESULT: one client call, 4 server receipts, elapsed=40.2s, returned_error=true

测试使用的 transport.rs 与 v0.6.0 原文件 SHA256 一致:446A74A1C895E6E2BD910F5339C3B4DDEF7485E3A76952465FDE6203FBE1C15F

提交检查

  • 我已确认内容不包含敏感凭据
  • 我已阅读仓库的 SECURITY.md

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions