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

Đang mở
#35,953 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
28/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
macos, rust, typescript
Lĩnh vực
desktop, security

Hướng nghiên cứu

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.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

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.
Ngôn ngữ chính
TypeScript
Star
24.8k
Fork
6.4k
Merge trung bình
59 phút
Pull request đã merge (30 ngày)
418

Chuẩn bị môi trường

Mở trong Codespaces

Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của pingdotgg/t3code

Tất cả issue của pingdotgg/t3code

Issue tương tự

Thêm issue về TypeScript

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.