Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).

Expand Down
23 changes: 20 additions & 3 deletions docs/CONTINUATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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.

Expand Down
6 changes: 5 additions & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@ const LEGACY_KEYS = ['deezerArl', 'spotifyDc'];

type Stored = { credentials?: Record<string, string>; recentUrls?: string[] } & Record<string, unknown>;

// 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');
Expand Down
Loading