From ea2450abfd2e340339964e740d8e24e396f5a8e9 Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Fri, 28 Aug 2026 15:24:29 +0100 Subject: [PATCH] feat(android): dire pourquoi le cache est illisible, et accepter un mot de passe comme code "Local vault unreadable" laissait croire a une corruption, donc a une perte, alors que le coffre est intact dans le depot. Quand Android a lui-meme detruit la cle - verrouillage d'ecran retire ou reinitialise - l'application le dit maintenant, et dit aussi que rien n'est perdu. Le tri passe par un drapeau pose la ou l'invalidation se constate, pas par un test sur le texte du message : c'est ce tri-la, fait sur des chaines, qui detruisait autrefois le cache en se trompant. Le code de deverrouillage accepte un mot de passe, et l'a toujours accepte - aucune validation n'a jamais impose des chiffres. Seul inputmode="numeric" le laissait croire, et le clavier numerique decourageait d'essayer. Clavier complet, libelles et note mis a jour. Co-Authored-By: Claude Opus 5 --- android-client/PMA.Store.pas | 16 ++++++++++++++++ android-client/web/app.html | 19 +++++++++++++------ mainApk.pas | 16 +++++++++++++++- 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/android-client/PMA.Store.pas b/android-client/PMA.Store.pas index de6eb84..fec9f5c 100644 --- a/android-client/PMA.Store.pas +++ b/android-client/PMA.Store.pas @@ -101,6 +101,15 @@ procedure SaveVault(const APlainJson, AETag, ASyncPwd: string; const ASalt: TBytes = nil; AIterations: Integer = 0; AClearPin: Boolean = False); +/// VRAI quand la derniere lecture a echoue parce que la cle protegee a ete +/// DETRUITE par le systeme - verrouillage d'ecran retire ou reinitialise. +/// +/// Un drapeau, et non un test sur le texte du message : c'est exactement ce +/// tri-la, fait sur des chaines, qui detruisait autrefois le cache en se +/// trompant. Ici l'information vient du systeme lui-meme, une seule fois, a +/// l'endroit ou elle est certaine. +function LastStoreKeyInvalidated: Boolean; + /// Le fichier local est-il scelle sous un code d'application ? Lu dans /// l'en-tete, sans rien dechiffrer. function VaultNeedsPin: Boolean; @@ -241,12 +250,18 @@ const var FLastStoreError: string = ''; + FLastStoreKeyInvalidated: Boolean = False; function LastStoreError: string; begin Result := FLastStoreError; end; +function LastStoreKeyInvalidated: Boolean; +begin + Result := FLastStoreKeyInvalidated; +end; + function LocalContainerPath: string; begin Result := TPath.Combine(TPath.GetHomePath, LOCAL_FILE); @@ -1217,6 +1232,7 @@ begin // rien ne pourra rouvrir. if Pos('KeyPermanentlyInvalidated', E.ClassName + E.Message) > 0 then try + FLastStoreKeyInvalidated := True; OpenKeyStore.deleteEntry(StringToJString(KEY_ALIAS_WRAP)); FLastStoreError := FLastStoreError + ' (cle invalidee, jetee)'; except diff --git a/android-client/web/app.html b/android-client/web/app.html index 6b1b79d..4a8c53f 100644 --- a/android-client/web/app.html +++ b/android-client/web/app.html @@ -410,8 +410,13 @@ JAMAIS PRE-REMPLI : le retenir reviendrait a ne rien proteger. -->
- + +
×
@@ -539,14 +544,16 @@

Unlock code

- +
×
-
The code seals the copy kept on this device. Removing it - leaves the vault readable by anyone holding the phone unlocked.
+
The code seals the copy kept on this device. It can be + digits or a full password - a longer one is harder to guess, and it is + asked for only when the vault opens. Removing it leaves the vault + readable by anyone holding the phone unlocked.

Diagnostics

diff --git a/mainApk.pas b/mainApk.pas index 449d629..e4174ad 100644 --- a/mainApk.pas +++ b/mainApk.pas @@ -2082,7 +2082,21 @@ begin FVaultUnreadable := True; ShowUnlock; Log('Local vault unreadable: ' + LastStoreError); - Status('Local vault unreadable - see log'); + // DIRE LAQUELLE DES DEUX. "Illisible" laisse croire a une corruption, donc + // a une perte - alors que le coffre est intact dans le depot et qu'il n'y a + // qu'a le reprendre. Quand le systeme a lui-meme detruit la cle parce que + // le verrouillage d'ecran a ete retire ou reinitialise, il faut le dire : + // c'est une consequence attendue d'un geste que l'utilisateur a fait, pas + // une panne. + if LastStoreKeyInvalidated then + begin + Status('Device protection changed - download the vault again'); + WebCall('PM.toast("This phone''s screen lock was removed or reset, so ' + + 'Android destroyed the key that sealed the local copy. ' + + 'Nothing is lost - the vault is in the repository.")'); + end + else + Status('Local vault unreadable - see log'); end; end;