Skip to content

fix(account): preflight the RPC chain in prepareCreateWithPasskey too (#445) - #448

Merged
jhfnetboy merged 1 commit into
masterfrom
fix/445-prepare-passkey-preflight
Aug 1, 2026
Merged

fix(account): preflight the RPC chain in prepareCreateWithPasskey too (#445)#448
jhfnetboy merged 1 commit into
masterfrom
fix/445-prepare-passkey-preflight

Conversation

@jhfnetboy

Copy link
Copy Markdown
Member

Closes #445

我在 #442 里漏掉的那个入口

#439/#442AccountService 加了 assertChainMatchesRpc,接在 prepareGuardianSetupsubmitCreateWithPasskey 上,漏了第三个 —— 而恰好是对那个 PR 自己宣称的目标最关键的那个。

prepareCreateWithPasskeyprepareCreateAccountWithPasskey 铸造 CREATE_ACCOUNT digest 和用户设备实际要签的 WebAuthn challenge 的地方。只在 submitCreateWithPasskey 检查是事后:到那一步,一次性仪式已经花在一个绑定到错误链的 digest 上了。

#442 拦住了错误的广播,但没有拦住它自己声称要拦的「白费一次仪式」。 这个 PR 把校验放到 digest 被铸造的地方,于是 CHAIN_ID/ETH_RPC_URL 不一致的代价从「一次 Face ID 提示 + 之后被拒」变成「一个 500」。

改动是一行 + 已存在的 helper。

测试(新增 2 个,本 spec 13 个,后端共 74)

11155111 / 10 / 8453:digest 只在链确认之后才铸造。不一致时 prepareCreateAccountWithPasskey 从未被调用 —— challenge 根本不会发出去。

变异验证非空测:去掉新加的 preflight 挂 4 个。

Gates

backend type-check + 74 tests + lint + format:check整棵树,两个 workspace)全绿。

Claude-Session: https://claude.ai/code/session_01BxmyQj2A82DfFXu97kKACk

…#445)

#439/#442 added `assertChainMatchesRpc` to prepareGuardianSetup and
submitCreateWithPasskey and missed the third entry point — which happens to be
the one that matters most for the goal that PR stated.

`prepareCreateWithPasskey` is where `prepareCreateAccountWithPasskey` mints the
CREATE_ACCOUNT digest and the WebAuthn challenge the user's device actually
signs. Checking only in submitCreateWithPasskey is after the fact: by then the
one-time ceremony has been spent on a digest bound to a chain the deploy will
not land on. #442 stopped the bad broadcast; it did not stop the wasted ceremony
it claimed to. This adds the check where the digest is minted, so a
CHAIN_ID/ETH_RPC_URL mismatch costs a 500 instead of a Face ID prompt.

One line plus the helper that already exists.

Tests (2 new, 13 in this spec, 74 total): across 11155111/10/8453 the digest is
minted only after the chain is confirmed, and on mismatch
`prepareCreateAccountWithPasskey` is never called — no challenge is handed out.
Verified non-vacuous by mutation: removing the new preflight fails 4.

Gates: backend type-check + 74 tests + lint + format:check (whole tree, both
workspaces) green.

Closes #445

Claude-Session: https://claude.ai/code/session_01BxmyQj2A82DfFXu97kKACk
@jhfnetboy
jhfnetboy requested a review from fanhousanbu as a code owner August 1, 2026 16:49
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@clestons clestons 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.

Review — #448 (fix(account): preflight the RPC chain in prepareCreateWithPasskey too, closes #445)

结论:APPROVE

补上了我在 #442 review 里标记、Codex PK 独立挖出的那个缺口:prepareCreateWithPasskeyprepareCreateAccountWithPasskey(SDK)真正铸造 CREATE_ACCOUNT digest 和用户设备要签的 WebAuthn challenge 的地方,之前只在 submitCreateWithPasskey 检查是"事后"——链不一致的代价之前是"白做一次 Face ID,之后才被拒",现在变成"直接 500,challenge 都不会发出去"。改动很小:一行 assertChainMatchesRpc() 调用,复用 #442 已经建好的 helper,不是新逻辑。

验证

  • 本地实跑:npx jest 74/74 全绿(9 suite,新增 2 条:跨 11155111/10/8453 确认 digest 只在链确认之后才铸造;不一致时 prepareCreateAccountWithPasskey 从未被调用,challenge 根本不会发出去);npx tsc --noEmit 干净。
  • 读了完整方法确认:新加的检查是函数里第一个异步/链相关操作,前面只有一个同步的 dailyLimit > 0 校验,没有任何东西会在检查之前被浪费——放置位置确实是最早可能的点。

PK Summary

  • R1 DeepSeek(flash):R1a+R1b 都跑了。R1a 提了个排序疑虑(检查放在 findUserById 之前"可能拒绝合法用户"),但它自己套用"反证规则"后自己撤回了,最终 finding 是空的——这是个不错的校准信号,不是瞎猜完就完事,会自己核实站不站得住。R1b 提了(Medium)"链检查在用户查找之前,用户不存在时可能泄露链不一致信息"——我核实这条不成立:assertChainMatchesRpc 根本不依赖 userId,是纯服务端配置检查,合法用户和不存在的用户在链不一致的情况下会拿到完全相同的错误(都在 findUserById 之前就被拦下),不存在"用户是否存在"的信息差。
  • Codex PK:独立 worktree。确认了我对 R1b 的驳回是对的(补充说明:这条检查最多泄露"全局部署配置错了"这种信息,不构成 R1b 声称的那种泄露);确认放置位置确实是最早点;专门检查了有没有第 4 个账户创建/passkey 入口漏掉——排查了 createWithP256Guardians,确认那是遗留的单次/无 owner WebAuthn 路径,不是另一个 prepare/challenge 铸造点,三个入口(prepareGuardianSetup/prepareCreateWithPasskey/submitCreateWithPasskey)现在确实都盖到了。

自评 — #448

  • 轮数:R1 DeepSeek(R1a+R1b 真跑)+ 我独立分析(含验证检查在函数里的绝对位置)+ 本地实跑 74/74 测试+tsc 干净 + Codex PK(1 轮,专门排查第 4 入口)。
  • 机械证据:npx jest 74/74、npx tsc --noEmit 干净,独立 worktree 真跑。
  • DeepSeek flash 评级:3/5 —— 没有直接可行动的真发现,但 R1a 自己提出又自己驳回的过程是个好信号(没有为了显得有用硬凑一条站不住的 finding,输出前有一层自我核实);R1b 那条被 Codex 独立确认不成立。样本 12/20,这条 chain-consistency 系列(#434#441/#442#448)是个很好的例子:从"完整 4-round 挖出问题"到"follow-up 一行修复+精准回归测试",链条走得很扎实。
  • 与 skill 设计一致,R1a+R1b 双通道 + Codex PK 都跑了。

R1 DeepSeek(R1a+R1b)真跑 + 独立分析(验证检查位置)+ 本地实跑 74/74 测试+tsc 干净 + Codex PK 1 轮(专门排查有无第 4 个漏掉的入口)。

@jhfnetboy
jhfnetboy merged commit 36b6dbe into master Aug 1, 2026
11 of 13 checks passed
@jhfnetboy
jhfnetboy deleted the fix/445-prepare-passkey-preflight branch August 1, 2026 17:08
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 1, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

account: prepareCreateWithPasskey 未做 RPC 链前置校验(#442 遗漏的第三个入口)

2 participants