feat(android): folder filter, icons, sort, template, updated_at, FLAG_SECURE
Works through the plan's §2 and §3 items that need no hardware and no platform decision. - allowBackup="false". The private directory holds vault.bin; a cloud backup has no business in a password manager's path, even though what would leave is encrypted by a key that stays in the chip. - FLAG_SECURE, Release builds only - in debug it also blocks development screenshots. Complementary to hiding on WillBecomeInactive rather than redundant: that one covers the recents preview, the flag also covers manual captures, screen recording and casting to an external display. - List sorted by name (snapshot order is DB order, arbitrary to the eye), entry icons decoded once per vault rather than on every keystroke, and a folder dropdown whose selection survives a background refresh. No tag filter: text search already matches tags. - template and updated_at read and shown in the detail. updated_at is also step 1 of the write path - nothing is arbitrable without it. Android code is now type-checked without deploying: dccaarm64 reaches the link step and fails only on the NDK's ldandroid.exe. A JNI declaration that does not compile no longer waits for an APK to say so. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+54
-29
@@ -61,17 +61,19 @@ retéléchargé, pas rester illisible. C'est l'autre branche de la même garde.
|
||||
|
||||
Par ordre de gravité, pas de taille.
|
||||
|
||||
1. **`android:allowBackup="false"`** dans
|
||||
[AndroidManifest.template.xml](../AndroidManifest.template.xml). Une ligne.
|
||||
Aujourd'hui absente : la sauvegarde Google peut donc emporter `vault.bin`.
|
||||
Le fichier est chiffré par une clé qui ne quitte pas la puce, donc ce qui
|
||||
sort est inexploitable — mais il sort, et le README prescrit déjà l'inverse.
|
||||
2. **Retirer `usesCleartextTraffic="true"`** du même fichier, et servir
|
||||
1. ~~**`android:allowBackup="false"`**~~ — **fait**. Le répertoire privé
|
||||
contient `vault.bin` ; la sauvegarde Google n'a rien à y faire, même si ce
|
||||
qui en sortirait serait chiffré par une clé restée dans la puce.
|
||||
2. **Retirer `usesCleartextTraffic="true"`** du manifeste, et servir
|
||||
l'endpoint en HTTPS avec un vrai certificat. L'attribut est marqué
|
||||
TEST-ONLY dans le manifeste ; le jeton Bearer circule à chaque appel.
|
||||
3. **`FLAG_SECURE`** sur la fenêtre. On masque déjà l'écran avant la capture
|
||||
des applications récentes, mais rien n'empêche une capture d'écran
|
||||
manuelle. `getWindow().setFlags` par JNI, quelques lignes.
|
||||
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.
|
||||
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.
|
||||
Complémentaire du masquage sur `WillBecomeInactive`, pas redondant : celui-ci
|
||||
traite l'aperçu des récentes, le drapeau traite en plus les captures
|
||||
manuelles, l'enregistrement d'écran et la duplication vers un écran externe.
|
||||
4. **Marquer le presse-papiers sensible** — depuis Android 13 le système
|
||||
affiche un aperçu de ce qui vient d'être copié, mot de passe compris.
|
||||
`ClipDescription` + extra `android.content.extra.IS_SENSITIVE`.
|
||||
@@ -89,17 +91,23 @@ Par ordre de gravité, pas de taille.
|
||||
Rangé par ce que ça apporte réellement sur un téléphone.
|
||||
|
||||
1. **Pièces jointes** — elles sont dans l'instantané, personne ne les lit.
|
||||
Lister nom/taille par entrée, et enregistrer via le sélecteur système.
|
||||
Attention à la mémoire : `content_b64` est déjà décodé en RAM avec tout le
|
||||
reste de l'instantané, un coffre avec des PDF pèse lourd.
|
||||
2. **Filtres dossier et étiquette.** `TVault.Search` ne prend qu'une requête
|
||||
texte ; ajouter deux paramètres facultatifs et une rangée de puces
|
||||
au-dessus de la liste. Les dossiers viennent du tableau `folders`.
|
||||
3. **Icônes** (`icon_b64`) en tête de ligne, à la place des initiales.
|
||||
Purement cosmétique, mais c'est ce qui rend une liste balayable.
|
||||
4. **`template`** — afficher le sous-type (carte, clé SSH…) comme le fait le
|
||||
poste Windows, et adapter les intitulés d'une carte bancaire.
|
||||
5. **Tri.** L'ordre actuel est celui de l'instantané. Par nom, au minimum.
|
||||
Lister nom/taille par entrée, et enregistrer. **Décision à prendre avant
|
||||
d'écrire quoi que ce soit** : où enregistrer sur Android 10+. Le répertoire
|
||||
privé de l'application ne sert à rien à l'utilisateur, et *Téléchargements*
|
||||
passe par `MediaStore` ou un `Intent` de partage. C'est cette question, pas
|
||||
le code, qui bloque. Attention aussi à la mémoire : `content_b64` est déjà
|
||||
décodé en RAM avec le reste de l'instantané, un coffre avec des PDF pèse.
|
||||
2. ~~**Filtre dossier**~~ — **fait**, liste déroulante à côté de la recherche,
|
||||
alimentée par le tableau `folders`, et le choix survit à un rafraîchissement
|
||||
de fond. **Pas de filtre d'étiquette** : la recherche texte couvre déjà les
|
||||
étiquettes, en taper le nom suffit.
|
||||
3. ~~**Icônes**~~ (`icon_b64`) — **fait**, décodées une fois par coffre et non à
|
||||
chaque frappe (la liste est reconstruite à chaque caractère). Une icône SVG
|
||||
n'est pas chargeable par FMX : l'entrée retombe sur ses initiales.
|
||||
4. ~~**`template`**~~ — **fait**, affiché comme *Type* dans le détail. Adapter
|
||||
en plus les intitulés d'une carte bancaire reste à voir.
|
||||
5. ~~**Tri par nom**~~ — **fait** dans `TVault.Search`. L'ordre de l'instantané
|
||||
est celui de la base, donc arbitraire à l'œil.
|
||||
6. **`TListView` à la place de `TListBox`** le jour où la reconstruction à
|
||||
chaque frappe se voit. Marqué `ponytail:` dans le code, pas avant.
|
||||
|
||||
@@ -128,9 +136,8 @@ d'interface d'édition.
|
||||
|
||||
### Dans l'ordre
|
||||
|
||||
1. **`updated_at` dans `TVaultEntry`.** Rien n'est arbitrable sans lui. À faire
|
||||
même si l'écriture est repoussée : la lecture peut déjà afficher « modifié
|
||||
le… ».
|
||||
1. ~~**`updated_at` dans `TVaultEntry`**~~ — **fait**, et déjà affiché comme
|
||||
*Modifié le* dans le détail. Rien n'était arbitrable sans lui.
|
||||
2. **AES-GCM en chiffrement.** On n'a que le déchiffrement, des deux côtés
|
||||
(JNI et CNG). Il faut aussi un sel de 32 octets et un IV de 12 octets tirés
|
||||
d'un générateur cryptographique — `SecureRandom` côté Android,
|
||||
@@ -171,8 +178,26 @@ tombstones ni génération d'uuid.
|
||||
|
||||
## Ordre proposé
|
||||
|
||||
1. Vérifier §1 sur téléphone — c'est ce qui valide le travail déjà fait.
|
||||
2. §2 items 1 et 2 : deux lignes de manifeste, et le risque le plus concret.
|
||||
3. §3 items 1 à 3 : pièces jointes, filtres, icônes. Le client devient
|
||||
réellement utilisable au quotidien.
|
||||
4. §4 étape 1 seule (`updated_at`), puis décider si l'écriture vaut son coût.
|
||||
1. **Vérifier §1 sur téléphone** — c'est ce qui valide le travail déjà fait, et
|
||||
rien d'autre ne peut le remplacer.
|
||||
2. §2 item 4 (presse-papiers sensible) puis 6 (verrouillage sur inactivité).
|
||||
3. §3 item 1, une fois tranché où atterrissent les pièces jointes.
|
||||
4. §4 à partir de l'étape 2, si l'écriture vaut son coût.
|
||||
|
||||
---
|
||||
|
||||
## Vérifier le code Android sans le déployer
|
||||
|
||||
Le compilateur croisé va jusqu'à l'édition de liens, qui échoue seulement
|
||||
parce que `ldandroid.exe` appartient au NDK et n'est pas dans le `PATH` :
|
||||
|
||||
```bash
|
||||
"C:\Program Files (x86)\Embarcadero\Studio\23.0\bin\dccaarm64.exe" -B "-UC:\Program Files (x86)\Embarcadero\Studio\23.0\lib\android64\release" pmserverApk.dpr
|
||||
```
|
||||
|
||||
`F1026 File not found: 'ldandroid.exe'` **sans erreur au-dessus** signifie que
|
||||
tout a compilé. C'est ce qui permet de valider des déclarations JNI sans
|
||||
attendre un APK — le pont construit ses signatures à partir des types déclarés,
|
||||
et une signature fausse ne se voyait jusqu'ici qu'à l'exécution. Cela ne
|
||||
prouve pas qu'une signature *correspond* à une méthode Java réelle, seulement
|
||||
qu'elle est cohérente : le déploiement reste le juge final.
|
||||
|
||||
Reference in New Issue
Block a user