[#3] Intégrité de subscription_status (anti-tampering gating licence) #80

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

Même après la migration des tokens vers le keychain (#78), account.json reste en clair sur disque et contient subscription_status utilisé par le gating de licence. Un malware local peut écrire "active" dedans pour contourner le paywall sans jamais toucher le keychain. Cette issue ferme ce trou.

Spec : spec-issue-66-oauth-keychain.md
Parent : #66
Dépendances : #78 (doit partager la même architecture que le nouveau token_store)
Ref : CWE-345 (Insufficient Verification of Data Authenticity)

Options (à trancher en début d'issue)

Option A — Re-validation systématique (préférée)
À chaque décision de gating (entitlements, auto-updater, features Pro), appeler refresh_auth_token() si le cache last_check a plus de N minutes, et trust uniquement la réponse de Logto fraîche. Le cache sur disque sert au démarrage hors-ligne mais n'est jamais source de vérité pour une action de gating.

Option B — Signature HMAC du cache
Signer account.json avec une clé HMAC stockée dans le keychain. Rejette toute modification manuelle.

Option C — Migrer account.json dans le keychain
Étendre le scope du #78 pour inclure account.json. Simple mais augmente la taille du blob keychain.

Tâches (Option A — à ajuster selon le choix)

  • Identifier tous les call sites qui lisent subscription_status depuis get_account_info pour prendre une décision de gating
  • Séparer get_account_info (affichage UI — OK de trust le cache) de get_subscription_status_verified (gating — force une call Logto si cache > 10min)
  • Nouvelle commande Tauri check_entitlement_verified() qui appelle toujours refresh_auth_token avant de retourner
  • Dans l'auto-updater gating et les features Pro, utiliser la commande vérifiée au lieu du cache
  • Graceful degradation : si offline, retomber sur le cache signé/horodaté avec un grace period (ex. 7 jours)

Critères d'acceptation

  • Écrire manuellement "active" dans account.json ne débloque aucune feature payante
  • L'app reste fonctionnelle offline pendant 7 jours avec un entitlement récemment vérifié
  • ADR ou section dans 0006-oauth-tokens-keychain.md documente l'option choisie
Même après la migration des tokens vers le keychain (#78), `account.json` reste en clair sur disque et contient `subscription_status` utilisé par le gating de licence. Un malware local peut écrire `"active"` dedans pour contourner le paywall **sans jamais toucher le keychain**. Cette issue ferme ce trou. **Spec :** `spec-issue-66-oauth-keychain.md` **Parent :** #66 **Dépendances :** #78 (doit partager la même architecture que le nouveau token_store) **Ref :** CWE-345 (Insufficient Verification of Data Authenticity) ## Options (à trancher en début d'issue) **Option A — Re-validation systématique (préférée)** À chaque décision de gating (entitlements, auto-updater, features Pro), appeler `refresh_auth_token()` si le cache `last_check` a plus de N minutes, et trust uniquement la réponse de Logto fraîche. Le cache sur disque sert au démarrage hors-ligne mais n'est jamais source de vérité pour une action de gating. **Option B — Signature HMAC du cache** Signer `account.json` avec une clé HMAC stockée dans le keychain. Rejette toute modification manuelle. **Option C — Migrer account.json dans le keychain** Étendre le scope du #78 pour inclure account.json. Simple mais augmente la taille du blob keychain. ## Tâches (Option A — à ajuster selon le choix) - [ ] Identifier tous les call sites qui lisent `subscription_status` depuis `get_account_info` pour prendre une décision de gating - [ ] Séparer `get_account_info` (affichage UI — OK de trust le cache) de `get_subscription_status_verified` (gating — force une call Logto si cache > 10min) - [ ] Nouvelle commande Tauri `check_entitlement_verified()` qui appelle toujours `refresh_auth_token` avant de retourner - [ ] Dans l'auto-updater gating et les features Pro, utiliser la commande vérifiée au lieu du cache - [ ] Graceful degradation : si offline, retomber sur le cache signé/horodaté avec un grace period (ex. 7 jours) ## Critères d'acceptation - [ ] Écrire manuellement `"active"` dans `account.json` ne débloque aucune feature payante - [ ] L'app reste fonctionnelle offline pendant 7 jours avec un entitlement récemment vérifié - [ ] ADR ou section dans `0006-oauth-tokens-keychain.md` documente l'option choisie
maximus added this to the spec-oauth-keychain milestone 2026-04-13 22:39:17 +00:00
maximus added the
status:ready
type:security
source:human
labels 2026-04-13 22:39:17 +00:00
maximus added
status:in-progress
and removed
status:ready
labels 2026-04-14 00:47:36 +00:00
maximus added
status:review
and removed
status:in-progress
labels 2026-04-14 12:08:55 +00:00
maximus added
status:approved
and removed
status:review
labels 2026-04-14 12:10:39 +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#80
No description provided.