feat(browser): add persistent auth profiles#2516
Conversation
…-auth-uaz1p # Conflicts: # apps/emdash-desktop/src/main/app/window.ts # apps/emdash-desktop/src/main/core/browser/browser-webcontents-registry.test.ts # apps/emdash-desktop/src/main/core/browser/browser-webcontents-registry.ts # apps/emdash-desktop/src/main/core/browser/controller.ts # apps/emdash-desktop/src/main/index.ts # apps/emdash-desktop/src/renderer/features/browser/browser-session-store.test.ts # apps/emdash-desktop/src/renderer/features/browser/browser-session-store.ts # apps/emdash-desktop/src/renderer/features/browser/browser-toolbar-actions.ts # apps/emdash-desktop/src/renderer/features/browser/browser-toolbar.tsx # apps/emdash-desktop/src/shared/browser.test.ts
Greptile SummaryThis PR replaces the old per-tab browser partitions with persistent named profiles backed by Electron sessions, adds profile CRUD in Settings, and hardens the in-app browser's security perimeter (permission deny-by-default, OAuth popup allowlist, user-agent scrubbing).
Confidence Score: 5/5Safe to merge. The partition migration, session hardening, and profile CRUD logic are sound with no data loss paths or security regressions. The two-step attach/bind model is correctly guarded, permission/navigation hardening is comprehensive, and cookie encryption is a one-way but well-documented change. The OAuth popup allowlist is intentionally conservative which may silently affect third-party sign-in flows but introduces no security risk. browser-partition-cleanup.ts — verify PROFILE_DIR_PREFIX matching correctly covers the default-profile directory which has no trailing dash.
|
| Filename | Overview |
|---|---|
| apps/emdash-desktop/src/main/core/browser/browser-webcontents-registry.ts | Major refactor: switched from partition→browserId map to pending/bound two-step model; added popup hardening, handleWebviewAttached, bindWebContents, and clearProfileStorage. |
| apps/emdash-desktop/src/renderer/features/browser/browser-session-store.ts | Added profileId field to sessions; setSessionProfile and migrateProfileSessions added; partition derivation now uses profile-based helpers. |
| apps/emdash-desktop/src/renderer/features/settings/components/BrowserSettingsCard.tsx | New 430-line component for profile management (add/rename/delete/clear); delete flow correctly clears storage, updates settings, and migrates open sessions. |
| apps/emdash-desktop/src/main/core/browser/browser-profile-session.ts | New module: configures each partition Session once with deny-by-default permissions, UA scrubbing, and Google-auth header override. |
| apps/emdash-desktop/src/main/core/browser/browser-partition-cleanup.ts | New module: removes old per-tab partition directories from userData on startup while preserving profile and isolated-task partitions. |
| apps/emdash-desktop/src/shared/browser.ts | Added profile types, constants, and partition helpers; deriveBrowserPartition replaced by browserProfilePartition/browserPartitionForProfile/makeIsolatedBrowserPartition. |
| apps/emdash-desktop/src/renderer/features/browser/browser-toolbar.tsx | Added profile switcher sub-menu wired to browserSessionStore.setSessionProfile and navigation to settings; settings query cached with Infinity GC time. |
Sequence Diagram
sequenceDiagram
participant R as Renderer (BrowserPane)
participant RPC as IPC / RPC
participant C as Controller (Main)
participant Reg as BrowserWebContentsRegistry
participant Ses as Electron Session
Note over R,Ses: Profile-aware session registration
R->>RPC: "registerSession({ browserId, partition })"
RPC->>C: registerSession
C->>Ses: configureBrowserProfileSession(partition)
Note right of Ses: Set UA, deny permissions,<br/>Google-auth header override (once)
C->>Reg: "registerSession({ browserId, partition })"
Note over R,Ses: Webview attach & bind
Ses-->>Reg: did-attach-webview(webContents)
Reg->>Reg: isRegisteredPartitionSession?
alt partition not registered
Reg->>Ses: webContents.close()
else partition registered
Reg->>Reg: pendingWebContentsIds.add(id)
Reg->>Reg: hardenBrowserWebContents()
R->>RPC: "bindWebContents({ browserId, webContentsId })"
RPC->>C: bindWebContents
C->>Reg: bindWebContents(browserId, webContents)
Reg->>Reg: browserIdByWebContentsId.set(id, browserId)
Reg->>Reg: "activeBrowserId = browserId"
end
Note over R,Ses: Profile switch
R->>R: browserSessionStore.setSessionProfile(browserId, newProfileId)
Note right of R: MobX: session.partition changes
R->>RPC: unregisterSession(browserId)
R->>RPC: "registerSession({ browserId, newPartition })"
Note right of R: Webview remounts (key change)
R->>RPC: "bindWebContents({ browserId, newWebContentsId })"
Reviews (2): Last reviewed commit: "fix(browser): tighten profile session ha..." | Re-trigger Greptile
Description
Screenshot/Recording (if applicable)
https://streamable.com/anzafl
Checklist
messages and, when possible, the PR title