garrytan / garrytan/gstack

cookie-import-browser: profile pills show stale creation-time names (11 Brave profiles → 5 labels, five reading "Profile 1")

Open Beginner friendly
#2,701 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
133k
Forks
19.9k
Avg merge
18h 46m
Merged PRs (30d)
26

Description

## Summary

The cookie picker's profile pills read profile display names from the wrong file. On Brave, 11 distinct profiles render as only 5 distinct labels, including five pills all reading "Profile 1". You cannot tell which profile you are about to import cookies from.

Root cause: `listProfiles()` reads `/Preferences` → `profile.name`, a legacy per-profile field that Chromium seeds at profile creation and does not update on rename. The authoritative display name lives at browser level in `Local State` → `profile.info_cache[].name`, which is what the browser's own profile switcher renders.

## Repro

1. Use Brave with several profiles renamed via the profile menu.
2. Run `browse cookie-import-browser`.
3. Select **Brave** as the source browser.
4. Observe the profile pills row.

## Evidence

Brave's own profile menu, all 11 names correct:

Image

The picker for the same 11 profiles:

Image

Calling the shipped `listProfiles()` directly:

```
dir Local State (truth) listProfiles() displayName
------------------------------------------------------------------
Default Personal "Personal" OK
Profile 5 Springboro Festivals "Profile 1"
Profile 6 Brian Retterer "Brian Retterer" OK
Profile 16 Boro After Prom "Profile 1"
Profile 17 Families of SHS "Profile 1"
Profile 18 Foster "Profile 1"
Profile 19 Warren County Astro "Profile 1"
Profile 22 Springboro Juneteenth "Person 1"
Profile 23 Artfest "Your Brave"
Profile 24 Collab Connect "Your Brave"
Profile 25 Ticket Committee "Person 1"

Ambiguous labels: "Profile 1" x5, "Person 1" x2, "Your Brave" x2
Total profiles: 11, distinct labels: 5
```

## Why the stale values look like this

The wrong labels are fossils of each profile's auto-generated name at creation time. They correlate exactly with the Brave build that created the profile:

```
created_by_version stale prefs_name
119.1.60.x 'Profile 1'
120.1.61.116 'Profile 1'
133.1.75.178 'Person 1'
137.1.79.118 'Your Brave'
138.1.80.120 'Your Brave'
148.1.90.122 'Person 1'
```

Those are Brave's default new-profile names across those eras. This confirms `Preferences` → `profile.name` is written once at creation and never refreshed on rename.

Supporting detail: only the two profiles that render correctly carry a `using_default_name: False` key in their own `Preferences`. The other nine have no such key. Meanwhile `Local State` → `info_cache` has `is_using_default_name: False` and the correct name for all 11. Two profiles created by the *same* build (Profile 5 and Profile 6) differ here, so this is about which rename path was used, not browser version.

## Why this survived

On Chrome the bug is usually masked. Signed-in Chrome profiles populate `account_info[0].email`, so the earlier branch in `listProfiles()` fires and yields a readable email. Brave has no Google sign-in, so `account_info` is always absent and every profile falls through to the stale field. In practice this is close to Brave-specific, which is the kind of gap that escapes Chrome-based testing.

## Impact

Not cosmetic. The picker's whole purpose is choosing which profile's cookies to import. With five identical "Profile 1" pills, selecting the intended profile is guesswork, and picking wrong imports the wrong session cookies into the headless browser: wrong account, wrong org, credentials the user did not intend to expose to an automated session.

## Origin

`listProfiles()` and the `account_info` lookup entered the tree in `22a4451` (v1.3.0.0). The design matches PR #121 ("Add profile picker to cookie import UI"), whose description states the premise directly:

> Profile display names are read from each profile's `Preferences` JSON (the same name shown in the browser's profile switcher), falling back to the directory name if unavailable.

That parenthetical is the defect. `Preferences` → `profile.name` is not the name in the profile switcher. So this is a mistaken assumption rather than a deliberate tradeoff. The described fallback does work as written, but never triggers, because the stale field is always present and always looks valid.

## Fix

Prefer `Local State` → `info_cache[dir].name`, falling back to the existing logic. `Local State` is already read in this same file (around line 492, for the v10 encryption key), so path resolution is proven.

In `browse/src/cookie-import-browser.ts`, `listProfiles()`:

```ts
// once, before the entry loop
let infoCache: Record = {};
try {
infoCache = JSON.parse(fs.readFileSync(path.join(browserDir, 'Local State'), 'utf-8'))
?.profile?.info_cache ?? {};
} catch { /* fall through to per-profile Preferences */ }

// inside the loop, ahead of the Preferences read
const cached = infoCache[entry.name]?.name;
if (typeof cached === 'string' && cached) {
displayName = cached;
} else {
// existing account_info / profile.name fallback
}
```

## Secondary nit (same area)

PR #121 describes the list as "sorted Default-first", but the returned order is raw `readdirSync` order: `Profile 17, 19, 18, 16, 6, Default, 22, 25, 24, 23, 5`. The pills render in that order, so `Default` lands sixth and the numbered profiles are not in numeric order. Selection is unaffected (the UI correctly auto-selects `Default`), so this is display ordering only. A sort would make the row much easier to scan.

## Environment

- gstack v1.69.0.0 (`ad84005`, at `origin/HEAD`, 0 commits behind)
- macOS 15 (Darwin 25.5.0), x64
- Brave Browser, 11 profiles
- Also affects Chrome installs where profiles are not signed in

---

🤖 Root cause investigation and this report drafted with [Claude Code](https://claude.com/claude-code). All findings (the `Local State` vs `Preferences` divergence, the `created_by_version` correlation, and the `listProfiles()` output) were verified directly against a live Brave install rather than inferred.

Contributor guide

Open the contributing guide

Research direction

Start in browse/src/cookie-import-browser.ts at listProfiles() and inspect the existing Local State read and per-profile Preferences fallback. Reproduce with `browse cookie-import-browser` using Brave profiles, then verify that the profile pills use Local State info_cache names and retain the fallback when unavailable.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
cli, frontend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
82/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.