diff --git a/android-client/PLAN.md b/android-client/PLAN.md index c13fe85..9c8ca3a 100644 --- a/android-client/PLAN.md +++ b/android-client/PLAN.md @@ -173,6 +173,7 @@ Par ordre de gravité, pas de taille. l'endpoint en HTTPS avec un vrai certificat. L'attribut est marqué TEST-ONLY ; le jeton Bearer circule à chaque appel. **Gardé pour l'instant** : le retirer casserait l'essai local par `adb reverse`, qui passe en clair. + Voir §6 : passer par Gitea réglerait ce point sans rien héberger de plus. 3. ~~**`FLAG_SECURE`**~~ — **fait**, [PMA.ScreenGuard.pas](PMA.ScreenGuard.pas), **en Release seulement** : en debug le drapeau interdit aussi les captures d'écran de développement. Le vérifier demande donc une compilation Release. @@ -328,6 +329,71 @@ tombstones ni génération d'uuid. --- +## 6. Remplacer l'endpoint par un dépôt Gitea + +Piste sérieuse pour le §2 item 2 : au lieu d'héberger `sync.php` en HTTPS avec +un certificat, déposer l'instantané chiffré dans un dépôt **privé** du Gitea +déjà en service. Plus rien à héberger, plus de certificat à renouveler, et +l'accès depuis l'extérieur vient gratuitement. + +**La mécanique tombe terme à terme sur ce qui est déjà écrit.** L'API rend le +fichier avec son `sha` et exige ce même `sha` pour écrire ; un `sha` périmé +donne un **409**. C'est exactement le rôle de l'`ETag` et du **412** : la +boucle relire-refusionner-renvoyer du poste Windows, bornée à trois essais, +fonctionne sans changer de forme. + +### Lire + +``` +GET /api/v1/repos/{owner}/{repo}/contents/vault-sync.json?ref=main +Authorization: token +``` + +Réponse : `{ "content": "", "encoding": "base64", "sha": "" }`. +Le `content` est le conteneur `pm-encrypted-export-v1`, déjà chiffré — Gitea ne +voit que des octets. Le `sha` prend la place de l'ETag, et se range avec le +coffre comme lui, puisqu'il décrit le clair détenu. + +**404** = pas encore d'instantané, à traiter comme le 404 actuel : premier +envoi, pas une erreur. + +### Écrire + +``` +PUT /api/v1/repos/{owner}/{repo}/contents/vault-sync.json +Authorization: token +{ "message": "sync", "content": "", "sha": "", + "branch": "main" } +``` + +Sans `sha`, Gitea refuse d'écraser un fichier existant ; avec un `sha` périmé +il répond **409**. C'est le `If-Match` qu'on avait dû implémenter à la main. + +### Le jeton + +Un jeton d'accès personnel **limité à ce dépôt**, droits `repo` en écriture. Il +remplace le jeton Bearer actuel et se range au même endroit — `settings.bin`, +scellé par la clé AES du Keystore, lisible sans authentification. Le +raisonnement ne change pas : il n'ouvre que du chiffré. + +### Ce que ça coûte, et pourquoi pas GitHub + +**L'historique de Git ne s'efface pas.** Chaque synchronisation est un commit, +et changer de mot de passe de sync n'enlève rien : toutes les versions +antérieures restent, chacune chiffrée sous le mot de passe de son époque. Un +ancien mot de passe faible resterait attaquable indéfiniment. Sur un serveur +qui écrase un fichier, ce problème n'existe pas. + +C'est vivable sur **son propre** Gitea — le disque est à soi, l'historique se +purge. Ça ne l'est pas sur GitHub, où le chiffré part chez un tiers, répliqué +et sauvegardé, avec un dépôt rendu public par erreur pour scénario du pire : +attaquable hors ligne, par n'importe qui, pour toujours. + +**À faire si on s'y engage** : un `PMA.SyncClient` qui parle cette API (le GET +authentifié existe déjà), la même chose côté poste Windows en remplacement de +WebDAV, et une purge périodique de l'historique — sans quoi le dépôt grossit +d'un instantané complet à chaque synchronisation, pièces jointes comprises. + ## Ordre proposé 1. **Vérifier §1 sur téléphone** — c'est ce qui valide le travail déjà fait, et