From 27289da9b2db11b405793ebd00fbc6040734e4be Mon Sep 17 00:00:00 2001 From: Native Muttaqien Date: Wed, 19 Aug 2026 15:23:04 +0700 Subject: [PATCH 1/2] fix: honour XDG_CONFIG_HOME on Windows so config dir is overridable configDir() checked win32 first and returned %APPDATA%\plx unconditionally, so the explicit override was ignored on exactly one platform. The test suite points XDG_CONFIG_HOME at a fresh temp dir per test for isolation, which meant every Windows test instead shared one real %APPDATA%\plx: a credential saved by one case was still there for the next, and config.test.ts:43 read back 'arl-value' where it expected ''. Both Windows legs of the CI matrix have been red since the matrix was added. Check the override before the platform branch. %APPDATA% stays the Windows default and ~/.config the Unix one; only the precedence changes. Co-Authored-By: Claude Opus 5 --- src/config.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/config.ts b/src/config.ts index e38f5fb..0c786cc 100644 --- a/src/config.ts +++ b/src/config.ts @@ -20,9 +20,13 @@ const LEGACY_KEYS = ['deezerArl', 'spotifyDc']; type Stored = { credentials?: Record; recentUrls?: string[] } & Record; +// XDG_CONFIG_HOME wins on every platform, Windows included: it is the explicit override, and a +// Windows-only branch that ignored it left the tests sharing one real %APPDATA% dir instead of a +// temp dir each, so state leaked between them. export function configDir(): string { + if (process.env.XDG_CONFIG_HOME) return join(process.env.XDG_CONFIG_HOME, 'plx'); if (platform() === 'win32') return join(process.env.APPDATA ?? join(homedir(), 'AppData', 'Roaming'), 'plx'); - return join(process.env.XDG_CONFIG_HOME ?? join(homedir(), '.config'), 'plx'); + return join(homedir(), '.config', 'plx'); } const file = () => join(configDir(), 'credentials.json'); From 9564961f54f6f6661ddadb4ef853e73343e9a31d Mon Sep 17 00:00:00 2001 From: Native Muttaqien Date: Wed, 19 Aug 2026 15:23:56 +0700 Subject: [PATCH 2/2] docs: correct the Windows/Firefox cookie notes and the CI matrix status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The out-of-scope note lumped Windows, Linux and Firefox together as "not done yet", which was wrong in both directions. Windows Chromium is not pending work but closed: App-Bound Encryption (Chrome 127+) wraps the cookie key in SYSTEM-DPAPI, and every bypass is malware behaviour. Firefox was listed as key4.db-encrypted, but key4.db holds logins — cookies.sqlite is plaintext on every OS, making it the one cheap backend, not a hard one. Also record why both Windows CI legs were red, and state in the README that Windows and Linux run plx fine and only lack the auto-fetch shortcut. Co-Authored-By: Claude Opus 5 --- README.md | 4 ++++ docs/CONTINUATION.md | 23 ++++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 60aecbd..3770282 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,10 @@ let it run automatically when a credential is missing. Works with the Chromium f Edge, Chromium, Vivaldi, Opera) and Safari (needs Full Disk Access). Manual paste stays the fallback everywhere else. +**Windows and Linux:** plx itself runs fine — every conversion works the same. Only this auto-fetch +shortcut is macOS-only, so paste the cookies once as described above and they're stored like any +other credential. + Set credentials in `.env`, export them in your shell, or paste when prompted. Full setup: [`docs/CONFIG.md`](docs/CONFIG.md). diff --git a/docs/CONTINUATION.md b/docs/CONTINUATION.md index 4867fc9..fc860df 100644 --- a/docs/CONTINUATION.md +++ b/docs/CONTINUATION.md @@ -204,8 +204,25 @@ OS permission dialog — and fall back to manual paste if nothing is found. `tryAutoFillCredentials(cfg)` — additive: env vars and stored credentials win, manual paste stays the fallback. First use pops the macOS Keychain "Allow" dialog. -Out of scope for now: Windows (DPAPI) / Linux (libsecret) cookie decrypt, and the -Firefox key4.db/encryptedcookies format. +Out of scope, with the reasons — these are not all equally hard: + +- **Windows, Chromium family — treat as closed, not merely unimplemented.** Plain + DPAPI only ever covered Chrome < 127. Since Chrome 127 (July 2024) App-Bound + Encryption stores cookies as `v20` blobs whose key is wrapped by User-DPAPI and + then SYSTEM-DPAPI, so only a SYSTEM process or `elevation_service.exe` can + unwrap it — the feature exists specifically 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. Do not ship it. +- **Linux, Chromium family** — libsecret/kwallet. Unimplemented, not blocked. +- **Firefox — the actually cheap one, and the note it replaces was wrong.** + `key4.db` protects saved *logins*, not cookies; `cookies.sqlite` stores cookie + values in **plaintext** on every OS. No DPAPI, no App-Bound Encryption, and it + reuses the `node:sqlite` import already here. One backend would cover Windows, + macOS and Linux at once. Gotchas: profile discovery via `profiles.ini`, and the + DB is WAL-mode and held open by the browser, so copy it (plus `-wal`) to a temp + file rather than relying on `readOnly: true`. + +If auto-fetch on Windows is ever asked for, Firefox is the answer; Chromium is not. ## Deezer → Spotify (WORKING — verified live) @@ -285,7 +302,7 @@ The hashes in `spotify.ts` (`ADD_TO_PLAYLIST_SHA`, `SEARCH_TRACKS_SHA`, `LIBRARY ## Release blockers -1. ~~Push to GitHub~~ — done (`4ca1db5`). **Confirm the CI matrix passes** (ubuntu/macos/windows × node 22/24) — pending. +1. ~~Push to GitHub~~ — done (`4ca1db5`). **CI matrix** (ubuntu/macos/windows × node 22/24): ubuntu and macos green; both **windows legs were red from the day the matrix landed** — `configDir()` ignored `XDG_CONFIG_HOME` on win32, so the per-test temp dirs collapsed onto one real `%APPDATA%\plx` and state leaked between cases (`config.test.ts:43`). Fixed on `fix/windows-config-dir`; confirm green there before merging. 2. ~~Fix the Deezer → Spotify reverse flow~~ — done, verified live (see "Verified live" above). 3. Publish `plx@0.1.0` to npm.