[Bug]: macOS browser import reports inaccessible encryption keys as missing

未关闭
#35,953 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
28/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
活跃
技术栈
macos, rust, typescript
领域
desktop, security

调研方向

Start with readKeychainSecret and the falsy-secret branch in apps/desktop/src/preview/BrowserImport/ChromiumKeys.ts, then the denial fixture in ChromiumKeys.test.ts. The root cause sits in the pinned @napi-rs/keyring 1.3.0 dependency (pnpm-lock.yaml), which converts native read errors to absent values, so the fix likely needs a dependency decision as well as code. Done means an access failure yields needsKeychainApproval, a missing key still yields keychainItemMissing, and a successful read is unchanged.

由索引模型根据 Issue 内容生成。

描述

vouch:denounced

Summary

When a macOS browser encryption-key read fails, browser import reports that the key does not exist and tells the user to sign in to the source browser again. An existing key that could not be read should retain its access failure so the user receives the appropriate approval or keyring error. A source trace through the exact pinned native binding establishes that it discards the failure before the application's error handler can see it; no real Keychain access was performed.

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Credentials, private paths, and sensitive data were excluded from this report.

Area

apps/desktop

Observed behavior

Source-only finding: the supported Chromium browser-import path on macOS calls AsyncEntry.getPassword(), but the resolved @napi-rs/keyring 1.3.0 implementation converts every native read error into an absent optional value. For an existing key whose platform read fails with an access error, T3 therefore takes the falsy-secret branch and produces keychainItemMissing, rather than taking the catch branch that produces needsKeychainApproval. The import error preserves that reason through ChromiumCookieReadError and BrowserImportFailedError, selecting the missing-key instruction to sign in to the source browser again.

Reproduction

  1. Inspect the desktop dependency resolution at the stated commit: pnpm-lock.yaml resolves @napi-rs/keyring to 1.3.0.
  2. Follow Settings → Browser → Browser profiles → Add profile → Import from a Chromium browser into BrowserImport.importCookies, readChromiumCookies, resolveChromiumKeys with platform darwin, and readKeychainSecret.
  3. Follow the published package's npm gitHead to PasswordTask.compute. For a platform result Err(NoStorageAccess), the .ok() conversion yields None and the N-API task resolves successfully with an absent value; it does not reject.
  4. Follow that value into readKeychainSecret: the catch handler is bypassed and the falsy-secret branch emits keychainItemMissing. Compare this with the rejected-promise denial fixture in ChromiumKeys.test.ts, which never models the pinned wrapper's error-erasing behavior.

These are source-inspection steps, not a native reproduction. The conversion is unconditional for any native read error. NOT_ENOUGH_INFO: the frequency of macOS users hitting native access failures was not measured; a disposable macOS account with a synthetic item and denied access would establish a live incident without exposing real credentials.

Reproduction script: NOT_ENOUGH_INFO — no native Keychain lookup was run, and there is no public dependency hook for injecting a native credential-store result. This report supplies the exact source path; a disposable macOS account or a native binding fixture would permit an executable end-to-end check.

Expected behavior

An inaccessible existing browser key must remain distinguishable from an absent key. T3 already represents these outcomes separately: its rejected-read handler produces needsKeychainApproval, and its missing-result handler produces keychainItemMissing in apps/desktop/src/preview/BrowserImport/ChromiumKeys.ts#L62-L75. The distinct user guidance is defined in packages/contracts/src/browserImport.ts#L79-L94, and apps/desktop/src/preview/BrowserImport/ChromiumKeys.test.ts#L114-L123 expects an access denial to retain the approval reason and original cause.

The pinned AsyncEntry declaration also documents missing and ambiguous results separately. The dependency's later released src/result.rs#L3-L16 preserves this distinction, mapping only NoEntry to absence and propagating other errors.

Impact and scope

Form impact: Minor bug or occasional failure.

Impact: P2 - Native read failures lose their cause and select an incorrect recovery instruction during macOS Chromium session import. The operation fails safely without importing cookies, but users are sent to source-browser sign-in instead of the actual access problem.

The source path is shared by the supported macOS Chromium browsers. Successful reads and genuinely missing keys are unaffected by this finding. Linux uses the separate libsecret helper and is outside this defect. NOT_ENOUGH_INFO: no native prompt was denied in this investigation, and no practical recovery procedure was exercised; those require a disposable macOS account with synthetic credentials.

Version

T3 Code commit 59e64eef881632a23f89c4138bcf37f23d92bf93. The desktop pnpm-lock.yaml#L434-L436 resolves @napi-rs/keyring 1.3.0. Its published npm metadata identifies gitHead e46be75c3ba8d5fde6b88a17c6153b87ffe4b946. No keyring patch exists in this checkout's patches directory. No dependency or installed application was changed.

Runtime and platform

Affects the desktop macOS Chromium import branch. Inspection ran on macOS arm64. No native keyring method, browser-secret executable, real credential, or Keychain item was accessed. NOT_ENOUGH_INFO: no affected packaged application's macOS version or architecture-specific native run was established; this is a source-only report against the pinned dependency and application code.

Interface

UI: desktop browser profile session import, backed by the @napi-rs/keyring AsyncEntry library API.

Earliest failure stage

Integration or transport: the native binding erases the credential-store read error before returning to TypeScript.

Relevant output or evidence

The exact dependency implementation is src/async_entry.rs#L247-L258. Its PasswordTask.compute contains:

fn compute(&mut self) -> Result<Self::Output> {
  Ok(self.inner.get_password().ok())
}

Thus Err(NoStorageAccess), Err(PlatformFailure), and Err(NoEntry) all become a successful absent optional result. The subsequent T3 read mapping cannot recover the discarded cause. ChromiumCookies.ts#L280-L289 and BrowserImport.ts#L316-L323 preserve the resulting missing-key reason to the import boundary.

The upstream Apple backend's keychain.rs#L360-L373 distinguishes item-not-found from access errors. The wrapper removes that distinction. Evidence provenance: static. Local verification: static-proof. Reproduction completeness: incomplete for a native macOS incident; complete for the conditional source path from a native read error to the incorrect application reason.

Expected outcome or recovery

For a native access-denied result, import reports an access/approval failure rather than claiming the key is absent. A genuinely missing key retains missing-key guidance, and a successful read still derives the same cookie key. A check of the released integration must exercise those three native outcomes, not just a JavaScript promise mock that rejects even though the pinned native implementation resolves.

Additional context

  • https://github.com/Brooooooklyn/keyring-node/pull/136 — reports and fixes this exact dependency error-erasure behavior; the discussion identifies its release in 2.0.0. The latest published 2.1.2 source also preserves non-missing errors, while this T3 checkout still resolves 1.3.0.
  • https://github.com/pingdotgg/t3code/pull/23157 — switched this T3 path to AsyncEntry and added resolved-undefined and rejected-denial mocks; its stated untested cases include denial on the async branch. Responsiveness is a separate contract from preserving native failure reasons.
  • https://github.com/pingdotgg/t3code/issues/29234 — concerns Linux KWallet attribute lookup rather than macOS native read-error translation; its remedy does not cover this path.
主要语言
TypeScript
星标
24.8k
派生
6.4k
平均合并
59 分钟
30 天内合并 PR
418

环境准备

在 Codespaces 中打开

在浏览器里用你自己的 GitHub 账号启动这个项目的开发容器。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

pingdotgg/t3code 的其他 Issue

查看 pingdotgg/t3code 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。