Repository navigation
feat: add a Firefox cookie backend, the first that works off macOS - #18
Merged
Merged
Conversation
Auto-fetch was macOS-only because both backends lean on the login Keychain. Firefox needs no keychain at all: cookies.sqlite stores values in plaintext on every OS, so one backend covers Windows, macOS and Linux and adds no dependency — node:sqlite was already imported for the Chromium DB. This is also the only route to auto-fetch on Windows. Chromium there is closed, not pending: since Chrome 127 App-Bound Encryption wraps the cookie key in SYSTEM-DPAPI, and every published bypass is COM hijacking or injection into the elevation service. Two things the backend has to get right: - Profiles are ranked by cookies.sqlite mtime, newest first, instead of parsing profiles.ini. Someone with several profiles is logged in on the one they last wrote to, which is what an mtime sort answers directly. - Firefox holds the DB open in WAL mode and on Windows that lock is enforced, so the DB is copied to a temp dir with its -wal sidecar and the copy is opened writable — replaying a WAL needs write access, and the sidecar holds cookies set this session that are not checkpointed yet. macOS behaviour is unchanged: the keychain-backed backends still run first and in their original order, with Firefox filling only what they left empty. Tested against real cookies.sqlite files built by node:sqlite — host ranking, profile ordering, and the failure paths. Firefox was not installed on the development machine, so this has not run against a genuine logged-in profile. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
plx | 6dd9237 | Commit Preview URL Branch Preview URL |
Aug 19 2026, 08:32 AM |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Auto-fetch has been macOS-only because both backends lean on the login Keychain. Firefox needs no keychain at all —
cookies.sqlitestores values in plaintext on every OS — so one backend covers Windows, macOS and Linux, with no new dependency (node:sqlitewas already imported for the Chromium DB).Why Firefox rather than Chromium-on-Windows
Chromium on Windows is closed, not pending. Since Chrome 127 (July 2024) App-Bound Encryption stores cookies as
v20blobs whose key is wrapped by User-DPAPI and then SYSTEM-DPAPI, so only a SYSTEM process orelevation_service.execan unwrap it — the feature exists precisely to stop what this module does. Every published bypass is COM hijacking or injection into the elevation service, which is malware behaviour and would get plx flagged as an infostealer.A related correction: the old note claimed Firefox cookies were
key4.db-encrypted. They aren't —key4.dbprotects saved logins. That mistake is what made the cheapest backend look like the hardest one.Two details that carry the implementation
Profile ranking by mtime, not
profiles.ini. Candidatecookies.sqlitefiles are sorted newest-written first. Someone with several profiles is logged in on the one they last wrote to, which is what an mtime sort answers directly — and it avoids an INI parser. The ordering test names its fixtures so alphabetical order is the opposite of mtime order, so a readdir that got it right by luck still fails.WAL handling. Firefox holds the DB open in WAL mode, and on Windows that lock is enforced — reading in place fails outright. The DB is copied to a temp dir along with its
-walsidecar (which holds cookies set this session, not yet checkpointed) and the copy is opened writable, because replaying a WAL requires write access.Blast radius
macOS behaviour is unchanged. The keychain-backed backends still run first, in their original order; Firefox only fills what they left empty. The
platform() !== 'darwin'early return became a per-backend gate rather than a gate on the whole function.Verification
124 tests pass (up from 116). The new ones run against real
cookies.sqlitefiles built bynode:sqliterather than stubs, covering the schema read, host ranking (including the.google.comvs.youtube.comcollision that silently breaks a YouTube Music session), profile ordering, the flat-layout fallback, and the not-a-database path.Not verified live: Firefox was not installed on the development machine, so this has never run against a genuine logged-in profile. That gap is recorded in
docs/CONTINUATION.mdrather than papered over. Worth one manual run before anyone leans on it.🤖 Generated with Claude Code