feat: migrate OAuth tokens from plaintext JSON to OS keychain #66

Closed
opened 2026-04-10 19:34:53 +00:00 by maximus · 1 comment
Owner

Contexte

Actuellement, les tokens OAuth (access + refresh) sont stockés en clair dans auth/tokens.json avec des permissions 0600 (Unix). Acceptable en pré-release mais à migrer vers le keychain OS.

Tâche

Migrer vers le keychain natif (Linux: libsecret, Windows: Credential Manager) via le crate keyring ou tauri-plugin-store.

Acceptance criteria

  • Tokens stockés dans le keychain OS
  • Fallback gracieux si keychain indisponible
  • Migration automatique des fichiers existants

Ref: CWE-312 (Cleartext Storage of Sensitive Information)
Related: #51

## Contexte Actuellement, les tokens OAuth (access + refresh) sont stockés en clair dans `auth/tokens.json` avec des permissions 0600 (Unix). Acceptable en pré-release mais à migrer vers le keychain OS. ## Tâche Migrer vers le keychain natif (Linux: libsecret, Windows: Credential Manager) via le crate `keyring` ou `tauri-plugin-store`. ## Acceptance criteria - Tokens stockés dans le keychain OS - Fallback gracieux si keychain indisponible - Migration automatique des fichiers existants Ref: CWE-312 (Cleartext Storage of Sensitive Information) Related: #51
Author
Owner

Revue multi-expert de la spec (#66)

Spec complète annotée dans spec-issue-66-oauth-keychain.md. Verdict : 🔴 CRITIQUES A CORRIGER avant implémentation.

6 critiques à corriger

  1. Bundle identifier — la spec utilise com.lacompagniemaximus.simpl-resultat mais tauri.conf.json déclare com.simpl.resultat. Aligner sur l'identifiant réel.
  2. Fallback save() silencieux — sur Windows le fallback n'applique aucune ACL ; un user .deb sans libsecret ne saurait pas que ses tokens sont en clair. DACL Windows ou fail-closed + état exposé au frontend.
  3. Plaintext récupérable post-migrationfs::remove_file ne zéroïfie pas les blocs. Overwrite + fsync avant delete.
  4. AppImage oubliébundle.targets inclut appimage, qui n'hérite pas des deps apt. Bundler via linuxdeploy, retirer, ou documenter.
  5. release.yml pas mis à jour — la spec ne parle que de check.yml. Le build release Linux cassera sans libsecret-1-dev dans release.yml aussi.
  6. check.yml mal lu — 2 jobs distincts (rust / frontend), seul rust a besoin de libsecret. Append à l'étape Install system dependencies existante.

7 améliorations

  • Module à placer dans src-tauri/src/commands/token_store.rs (pas de nouveau top-level auth/)
  • Flag store_mode persistant pour détecter les downgrades hostiles
  • Migration auto : remplacer TOKENS_FILE.exists() par token_store::load()?.is_some() à auth_commands.rs:320
  • Pinner keyring = "3.x" + cargo audit en CI
  • subscription_status doit être re-validé/signé (tampering bypasse le gating licence)
  • Drop le trait Backend injection (YAGNI, keyring v3 n'expose pas de trait)
  • ADR : 0006-oauth-tokens-keychain.md (pas adr-006-), changelog sous Changed pas Security

Estimation revue

Spec : 2h30-3h → réel : 4-5h (CI debug cycles, linking libsecret, validation libs manquantes).

Prochain pas : mettre à jour la spec pour intégrer ces 13 points, puis créer la branche d'implémentation.

## Revue multi-expert de la spec (#66) Spec complète annotée dans `spec-issue-66-oauth-keychain.md`. Verdict : 🔴 **CRITIQUES A CORRIGER** avant implémentation. ### 6 critiques à corriger 1. **Bundle identifier** — la spec utilise `com.lacompagniemaximus.simpl-resultat` mais `tauri.conf.json` déclare `com.simpl.resultat`. Aligner sur l'identifiant réel. 2. **Fallback save() silencieux** — sur Windows le fallback n'applique aucune ACL ; un user .deb sans libsecret ne saurait pas que ses tokens sont en clair. DACL Windows ou fail-closed + état exposé au frontend. 3. **Plaintext récupérable post-migration** — `fs::remove_file` ne zéroïfie pas les blocs. Overwrite + fsync avant delete. 4. **AppImage oublié** — `bundle.targets` inclut appimage, qui n'hérite pas des deps apt. Bundler via linuxdeploy, retirer, ou documenter. 5. **release.yml pas mis à jour** — la spec ne parle que de check.yml. Le build release Linux cassera sans `libsecret-1-dev` dans release.yml aussi. 6. **check.yml mal lu** — 2 jobs distincts (`rust` / `frontend`), seul `rust` a besoin de libsecret. Append à l'étape *Install system dependencies* existante. ### 7 améliorations - Module à placer dans `src-tauri/src/commands/token_store.rs` (pas de nouveau top-level `auth/`) - Flag `store_mode` persistant pour détecter les downgrades hostiles - Migration auto : remplacer `TOKENS_FILE.exists()` par `token_store::load()?.is_some()` à auth_commands.rs:320 - Pinner `keyring = "3.x"` + `cargo audit` en CI - `subscription_status` doit être re-validé/signé (tampering bypasse le gating licence) - Drop le trait Backend injection (YAGNI, keyring v3 n'expose pas de trait) - ADR : `0006-oauth-tokens-keychain.md` (pas `adr-006-`), changelog sous `Changed` pas `Security` ### Estimation revue Spec : 2h30-3h → réel : **4-5h** (CI debug cycles, linking libsecret, validation libs manquantes). Prochain pas : mettre à jour la spec pour intégrer ces 13 points, puis créer la branche d'implémentation.
maximus added this to the spec-oauth-keychain milestone 2026-04-13 22:40:52 +00:00
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: maximus/Simpl-Resultat#66
No description provided.