[#1] Module token_store + refactor auth_commands.rs (coeur migration) #78

Closed
opened 2026-04-13 22:38:24 +00:00 by maximus · 0 comments
Owner

Implementation du module token_store qui remplace tous les accès direct au fichier tokens.json dans auth_commands.rs, avec fallback gracieux et migration transparente.

Spec : spec-issue-66-oauth-keychain.md
Parent : #66
Dépendances : aucune (première issue du milestone)

Tâches

Dépendances Rust

  • Ajouter keyring = "3.x" dans src-tauri/Cargo.toml (pin explicite)

Module token_store

  • Créer src-tauri/src/commands/token_store.rs (pas de nouveau top-level auth/)
  • Enregistrer dans src-tauri/src/commands/mod.rs
  • Utiliser service = "com.simpl.resultat" (identifiant canonique de tauri.conf.json, PAS com.lacompagniemaximus.simpl-resultat)
  • user = "oauth-tokens", valeur = JSON compact de StoredTokens
  • save(app, tokens) -> Result<(), String> — keyring d'abord, fallback write_restricted() si KO
  • load(app) -> Result<Option<StoredTokens>, String> — keyring d'abord, puis migration depuis tokens.json si présent
  • delete(app) -> Result<(), String> — efface keychain ET fichier résiduel

Migration sécurisée

  • Avant fs::remove_file du fichier migré : overwrite avec zéros + fsync(), PUIS delete (CWE-212)
  • Documenter dans le commentaire que les backups existants peuvent toujours contenir les vieux tokens

Flag store_mode

  • Persister un flag store_mode dans app_data_dir/auth/ pour distinguer keychain-réussi-une-fois vs jamais-marché
  • Si keychain a déjà fonctionné et échoue ensuite : refuser l'écriture plaintext et forcer reauth (pas de downgrade silencieux, CWE-757)

Refactor auth_commands.rs

  • handle_auth_callback (l.202) : token_store::save(&app, &tokens)
  • refresh_auth_token (l.219-227) : token_store::load(&app)?
  • refresh_auth_token (l.277) : token_store::save(&app, &new_tokens)
  • refresh_auth_token (l.251) : token_store::delete(&app) sur échec refresh
  • logout (l.305) : token_store::delete(&app)
  • check_subscription_status (l.320) : remplacer dir.join(TOKENS_FILE).exists() par token_store::load(&app)?.is_some()important : ça déclenche la migration même quand le throttle 24h early-return
  • Supprimer la constante TOKENS_FILE de auth_commands.rs

Tests

  • Test serde round-trip StoredTokens
  • Test du chemin fallback fichier (sans keyring)
  • Tests qui touchent un vrai keychain marqués #[ignore]
  • PAS de trait Backend d'injection — YAGNI, keyring v3 expose une struct concrète

Critères d'acceptation

  • cargo check et cargo test passent
  • Aucune référence à TOKENS_FILE / tokens.json ne reste dans auth_commands.rs
  • Le module token_store compile indépendamment
  • Service keychain utilise bien com.simpl.resultat
Implementation du module `token_store` qui remplace tous les accès direct au fichier `tokens.json` dans `auth_commands.rs`, avec fallback gracieux et migration transparente. **Spec :** `spec-issue-66-oauth-keychain.md` **Parent :** #66 **Dépendances :** aucune (première issue du milestone) ## Tâches ### Dépendances Rust - [ ] Ajouter `keyring = "3.x"` dans `src-tauri/Cargo.toml` (pin explicite) ### Module token_store - [ ] Créer `src-tauri/src/commands/token_store.rs` (pas de nouveau top-level `auth/`) - [ ] Enregistrer dans `src-tauri/src/commands/mod.rs` - [ ] Utiliser `service = "com.simpl.resultat"` (identifiant canonique de tauri.conf.json, PAS `com.lacompagniemaximus.simpl-resultat`) - [ ] `user = "oauth-tokens"`, valeur = JSON compact de `StoredTokens` - [ ] `save(app, tokens) -> Result<(), String>` — keyring d'abord, fallback `write_restricted()` si KO - [ ] `load(app) -> Result<Option<StoredTokens>, String>` — keyring d'abord, puis migration depuis `tokens.json` si présent - [ ] `delete(app) -> Result<(), String>` — efface keychain ET fichier résiduel ### Migration sécurisée - [ ] Avant `fs::remove_file` du fichier migré : overwrite avec zéros + `fsync()`, PUIS delete (CWE-212) - [ ] Documenter dans le commentaire que les backups existants peuvent toujours contenir les vieux tokens ### Flag store_mode - [ ] Persister un flag `store_mode` dans `app_data_dir/auth/` pour distinguer keychain-réussi-une-fois vs jamais-marché - [ ] Si keychain a déjà fonctionné et échoue ensuite : refuser l'écriture plaintext et forcer reauth (pas de downgrade silencieux, CWE-757) ### Refactor auth_commands.rs - [ ] `handle_auth_callback` (l.202) : `token_store::save(&app, &tokens)` - [ ] `refresh_auth_token` (l.219-227) : `token_store::load(&app)?` - [ ] `refresh_auth_token` (l.277) : `token_store::save(&app, &new_tokens)` - [ ] `refresh_auth_token` (l.251) : `token_store::delete(&app)` sur échec refresh - [ ] `logout` (l.305) : `token_store::delete(&app)` - [ ] `check_subscription_status` (l.320) : remplacer `dir.join(TOKENS_FILE).exists()` par `token_store::load(&app)?.is_some()` — **important : ça déclenche la migration même quand le throttle 24h early-return** - [ ] Supprimer la constante `TOKENS_FILE` de auth_commands.rs ### Tests - [ ] Test serde round-trip `StoredTokens` - [ ] Test du chemin fallback fichier (sans keyring) - [ ] Tests qui touchent un vrai keychain marqués `#[ignore]` - [ ] PAS de trait `Backend` d'injection — YAGNI, keyring v3 expose une struct concrète ## Critères d'acceptation - [ ] `cargo check` et `cargo test` passent - [ ] Aucune référence à `TOKENS_FILE` / `tokens.json` ne reste dans `auth_commands.rs` - [ ] Le module token_store compile indépendamment - [ ] Service keychain utilise bien `com.simpl.resultat`
maximus added this to the spec-oauth-keychain milestone 2026-04-13 22:38:24 +00:00
maximus added the
status:ready
type:refactor
type:security
source:human
labels 2026-04-13 22:38:24 +00:00
maximus added
status:in-progress
and removed
status:ready
labels 2026-04-13 22:47:23 +00:00
maximus added
status:review
and removed
status:in-progress
labels 2026-04-13 23:55:33 +00:00
maximus added
status:approved
and removed
status:review
labels 2026-04-14 00:11:21 +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#78
No description provided.