feat(android): show first, sync after
The local vault now opens by itself at launch and the GET runs behind it, silently. A 304 shows nothing; a network failure shows nothing either - offline is a normal state, and an alert on every launch only teaches people to dismiss alerts. Only a new snapshot manifests, by refreshing the list. That silence is what puts the sync password inside the Keystore-encrypted file next to the vault: without it a new snapshot cannot be opened, so every edit made on the desktop would raise a password prompt at launch. The file already holds every password in plaintext; this one adds almost nothing to its exposure. A typed password still wins over the stored one, which is how you fix one that no longer works. Adopting a snapshot while the app is already open rebuilds the list in place instead of navigating - mandatory even from the detail screen, since list rows carry indices into the old vault and a tap would open the wrong entry. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -75,11 +75,10 @@ Par ordre de gravité, pas de taille.
|
|||||||
4. **Marquer le presse-papiers sensible** — depuis Android 13 le système
|
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.
|
affiche un aperçu de ce qui vient d'être copié, mot de passe compris.
|
||||||
`ClipDescription` + extra `android.content.extra.IS_SENSITIVE`.
|
`ClipDescription` + extra `android.content.extra.IS_SENSITIVE`.
|
||||||
5. **Sortir les paramètres du code source.** URL, jeton et mot de passe de
|
5. **Sortir l'URL et le jeton du code source.** Ce sont encore des constantes.
|
||||||
sync sont des constantes, et le mot de passe vient d'un fichier hors dépôt
|
Le mot de passe de sync, lui, est déjà rangé dans le fichier chiffré par le
|
||||||
([PMA.LocalConfig.inc](PMA.LocalConfig.template.inc)). Un vrai client les
|
Keystore ; reste à en faire autant pour les deux autres, et à supprimer le
|
||||||
demande une fois et les range dans le même fichier chiffré par le Keystore
|
préremplissage depuis [PMA.LocalConfig.inc](PMA.LocalConfig.template.inc).
|
||||||
que le coffre.
|
|
||||||
6. **Verrouillage sur inactivité au premier plan.** Aujourd'hui seul le
|
6. **Verrouillage sur inactivité au premier plan.** Aujourd'hui seul le
|
||||||
passage en arrière-plan verrouille ; le poste Windows a en plus une minuterie.
|
passage en arrière-plan verrouille ; le poste Windows a en plus une minuterie.
|
||||||
|
|
||||||
|
|||||||
@@ -13,17 +13,17 @@ unit PMA.Store;
|
|||||||
n'en sort pas : on envoie des donnees a chiffrer, on recoit le resultat. Un
|
n'en sort pas : on envoie des donnees a chiffrer, on recoit le resultat. Un
|
||||||
vol du fichier seul est donc inexploitable, meme root - il faut la puce.
|
vol du fichier seul est donc inexploitable, meme root - il faut la puce.
|
||||||
|
|
||||||
CE QUE CE FICHIER CONTIENT : tous les mots de passe en clair, une fois
|
CE QUE CE FICHIER CONTIENT : tous les mots de passe en clair une fois
|
||||||
dechiffre. D'ou trois regles tenues ici :
|
dechiffre, ET le mot de passe de sync (voir SaveVault pour l'arbitrage).
|
||||||
|
D'ou trois regles tenues ici :
|
||||||
- jamais hors du repertoire prive de l'application ;
|
- jamais hors du repertoire prive de l'application ;
|
||||||
- jamais de copie en clair sur le disque, meme temporaire ;
|
- jamais de copie en clair sur le disque, meme temporaire ;
|
||||||
- la sauvegarde automatique Android doit etre desactivee pour l'app
|
- la sauvegarde automatique Android doit etre desactivee pour l'app
|
||||||
(android:allowBackup="false"), sinon Google en recupere une copie.
|
(android:allowBackup="false"), sinon Google en recupere une copie.
|
||||||
|
|
||||||
PAS ENCORE FAIT : exiger la biometrie a chaque lecture
|
La biometrie est demandee a la lecture quand la cle a pu etre creee avec
|
||||||
(setUserAuthenticationRequired). La cle est deja liee au materiel ; la
|
setUserAuthenticationRequired - deux alias existent pour cela, et l'en-tete
|
||||||
biometrie ajouterait une barriere si le telephone est deverrouille et qu'un
|
du fichier dit lequel a servi.
|
||||||
tiers ouvre l'application. A faire dans un second temps, avec BiometricPrompt.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface
|
interface
|
||||||
@@ -37,12 +37,22 @@ type
|
|||||||
/// Le coffre local existe-t-il ?
|
/// Le coffre local existe-t-il ?
|
||||||
function HasVault: Boolean;
|
function HasVault: Boolean;
|
||||||
|
|
||||||
/// Ecrit le coffre et l'ETag qui l'accompagne, chiffres ensemble.
|
/// Ecrit le coffre, l'ETag qui l'accompagne et le mot de passe de sync,
|
||||||
|
/// chiffres ensemble.
|
||||||
|
///
|
||||||
|
/// POURQUOI LE MOT DE PASSE EST LA : sans lui, un instantane nouveau ne peut
|
||||||
|
/// pas etre ouvert sans intervention, et chaque modification faite sur le
|
||||||
|
/// poste ferait apparaitre une demande de mot de passe au lancement - que
|
||||||
|
/// l'utilisateur finirait par expedier sans la lire. Le fichier contient deja
|
||||||
|
/// tous les mots de passe en clair ; celui-ci n'y ajoute presque rien en
|
||||||
|
/// exposition, et rend la synchronisation silencieuse.
|
||||||
|
///
|
||||||
/// ARequireAuth demande une cle deverrouillee par biometrie ou code. Si
|
/// ARequireAuth demande une cle deverrouillee par biometrie ou code. Si
|
||||||
/// l'appareil n'a aucune de ces protections, on retombe silencieusement sur
|
/// l'appareil n'a aucune de ces protections, on retombe silencieusement sur
|
||||||
/// une cle sans contrainte : mieux vaut un cache lie au materiel que pas de
|
/// une cle sans contrainte : mieux vaut un cache lie au materiel que pas de
|
||||||
/// cache du tout. VaultNeedsAuth dira ensuite ce qui a reellement ete fait.
|
/// cache du tout. VaultNeedsAuth dira ensuite ce qui a reellement ete fait.
|
||||||
procedure SaveVault(const APlainJson, AETag: string; ARequireAuth: Boolean = False);
|
procedure SaveVault(const APlainJson, AETag, ASyncPwd: string;
|
||||||
|
ARequireAuth: Boolean = False);
|
||||||
|
|
||||||
/// Le coffre local exige-t-il une authentification pour etre lu ? Lu dans
|
/// Le coffre local exige-t-il une authentification pour etre lu ? Lu dans
|
||||||
/// l'en-tete du fichier, sans dechiffrer quoi que ce soit.
|
/// l'en-tete du fichier, sans dechiffrer quoi que ce soit.
|
||||||
@@ -50,7 +60,9 @@ function VaultNeedsAuth: Boolean;
|
|||||||
|
|
||||||
/// Relit le coffre. False si absent ou illisible (cle perdue apres une
|
/// Relit le coffre. False si absent ou illisible (cle perdue apres une
|
||||||
/// reinstallation, fichier altere) - dans ce cas il faut retelecharger.
|
/// reinstallation, fichier altere) - dans ce cas il faut retelecharger.
|
||||||
function LoadVault(out APlainJson, AETag: string): Boolean;
|
/// ASyncPwd est vide pour un fichier ecrit avant que le mot de passe y soit
|
||||||
|
/// range : l'appelant redemande alors, et le prochain enregistrement le pose.
|
||||||
|
function LoadVault(out APlainJson, AETag, ASyncPwd: string): Boolean;
|
||||||
|
|
||||||
/// Efface le coffre local. A appeler au moindre doute : il se retelecharge.
|
/// Efface le coffre local. A appeler au moindre doute : il se retelecharge.
|
||||||
procedure ClearVault;
|
procedure ClearVault;
|
||||||
@@ -311,7 +323,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure SaveVault(const APlainJson, AETag: string; ARequireAuth: Boolean);
|
procedure SaveVault(const APlainJson, AETag, ASyncPwd: string;
|
||||||
|
ARequireAuth: Boolean);
|
||||||
{$IF DEFINED(ANDROID)}
|
{$IF DEFINED(ANDROID)}
|
||||||
var
|
var
|
||||||
LWrap: TJSONObject;
|
LWrap: TJSONObject;
|
||||||
@@ -326,6 +339,7 @@ begin
|
|||||||
LWrap := TJSONObject.Create;
|
LWrap := TJSONObject.Create;
|
||||||
try
|
try
|
||||||
LWrap.AddPair('etag', AETag);
|
LWrap.AddPair('etag', AETag);
|
||||||
|
LWrap.AddPair('pwd', ASyncPwd);
|
||||||
LWrap.AddPair('vault', APlainJson);
|
LWrap.AddPair('vault', APlainJson);
|
||||||
LPlain := TEncoding.UTF8.GetBytes(LWrap.ToJSON);
|
LPlain := TEncoding.UTF8.GetBytes(LWrap.ToJSON);
|
||||||
finally
|
finally
|
||||||
@@ -367,7 +381,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
|
|
||||||
function LoadVault(out APlainJson, AETag: string): Boolean;
|
function LoadVault(out APlainJson, AETag, ASyncPwd: string): Boolean;
|
||||||
{$IF DEFINED(ANDROID)}
|
{$IF DEFINED(ANDROID)}
|
||||||
var
|
var
|
||||||
LRaw, LIv, LCt, LPlain: TBytes;
|
LRaw, LIv, LCt, LPlain: TBytes;
|
||||||
@@ -377,6 +391,7 @@ begin
|
|||||||
Result := False;
|
Result := False;
|
||||||
APlainJson := '';
|
APlainJson := '';
|
||||||
AETag := '';
|
AETag := '';
|
||||||
|
ASyncPwd := '';
|
||||||
if not TFile.Exists(VaultPath) then Exit;
|
if not TFile.Exists(VaultPath) then Exit;
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -402,6 +417,7 @@ begin
|
|||||||
if LWrap = nil then Exit;
|
if LWrap = nil then Exit;
|
||||||
try
|
try
|
||||||
AETag := LWrap.GetValue<string>('etag', '');
|
AETag := LWrap.GetValue<string>('etag', '');
|
||||||
|
ASyncPwd := LWrap.GetValue<string>('pwd', '');
|
||||||
APlainJson := LWrap.GetValue<string>('vault', '');
|
APlainJson := LWrap.GetValue<string>('vault', '');
|
||||||
Result := APlainJson <> '';
|
Result := APlainJson <> '';
|
||||||
finally
|
finally
|
||||||
@@ -431,6 +447,7 @@ begin
|
|||||||
Result := False;
|
Result := False;
|
||||||
APlainJson := '';
|
APlainJson := '';
|
||||||
AETag := '';
|
AETag := '';
|
||||||
|
ASyncPwd := '';
|
||||||
end;
|
end;
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,21 @@ Trois écrans dans une seule forme, construits en code (`mainApk.pas`) :
|
|||||||
déverrouillage, liste, détail. Une forme par écran aurait coûté trois `.fmx`
|
déverrouillage, liste, détail. Une forme par écran aurait coûté trois `.fmx`
|
||||||
pour des dispositions triviales.
|
pour des dispositions triviales.
|
||||||
|
|
||||||
|
**Afficher d'abord, synchroniser ensuite.** Au lancement, le coffre local
|
||||||
|
s'ouvre tout seul (biométrie si la clé l'exige) et la liste apparaît sans
|
||||||
|
réseau ni dérivation ; le `GET` part derrière, en silence. Un 304 ne se voit
|
||||||
|
pas, un échec réseau non plus — hors ligne est un état normal, et une alerte à
|
||||||
|
chaque lancement apprendrait surtout à ignorer les alertes. Seul un instantané
|
||||||
|
**nouveau** se manifeste, en rafraîchissant la liste.
|
||||||
|
|
||||||
|
C'est ce qui justifie de ranger le **mot de passe de sync** dans le fichier
|
||||||
|
chiffré, à côté du coffre : sans lui, un instantané nouveau ne peut pas être
|
||||||
|
ouvert, et chaque modification faite sur le poste ferait apparaître une invite
|
||||||
|
au lancement. Le fichier contient déjà tous les mots de passe en clair ;
|
||||||
|
celui-ci n'y ajoute presque rien en exposition. Ce qui est tapé dans le champ
|
||||||
|
l'emporte sur ce qui est rangé — c'est ainsi qu'on corrige un mot de passe qui
|
||||||
|
ne convient plus.
|
||||||
|
|
||||||
L'écran de déverrouillage s'adapte à ce que l'appareil détient : coffre local
|
L'écran de déverrouillage s'adapte à ce que l'appareil détient : coffre local
|
||||||
présent → *Ouvrir* (biométrie si la clé l'exige) ; absent → seul le
|
présent → *Ouvrir* (biométrie si la clé l'exige) ; absent → seul le
|
||||||
téléchargement peut en produire un. La liste filtre à la frappe sur le nom, le
|
téléchargement peut en produire un. La liste filtre à la frappe sur le nom, le
|
||||||
|
|||||||
+63
-13
@@ -75,6 +75,10 @@ type
|
|||||||
// economiser un telechargement pour se retrouver sans donnees.
|
// economiser un telechargement pour se retrouver sans donnees.
|
||||||
FETag: string;
|
FETag: string;
|
||||||
FBusy: Boolean;
|
FBusy: Boolean;
|
||||||
|
// Mot de passe de sync tel qu'il a ete range avec le coffre. Il rend le
|
||||||
|
// rafraichissement de fond silencieux : sans lui, chaque modification
|
||||||
|
// faite sur le poste ferait apparaitre une invite au lancement.
|
||||||
|
FSyncPwd: string;
|
||||||
|
|
||||||
// --- ecran 1 : deverrouillage
|
// --- ecran 1 : deverrouillage
|
||||||
FLayUnlock: TLayout;
|
FLayUnlock: TLayout;
|
||||||
@@ -126,7 +130,11 @@ type
|
|||||||
// procedure imbriquee (E2555), et le rappel de la biometrie en est une.
|
// procedure imbriquee (E2555), et le rappel de la biometrie en est une.
|
||||||
procedure OpenLocalNow;
|
procedure OpenLocalNow;
|
||||||
procedure DoSync(Sender: TObject);
|
procedure DoSync(Sender: TObject);
|
||||||
procedure FetchAndDecrypt(const AUrl, ATok, APwd: string);
|
/// ASilent : rafraichissement de fond. Le coffre local est deja affiche,
|
||||||
|
/// donc un echec reseau ne doit rien reclamer a l'utilisateur - il garde
|
||||||
|
/// ce qu'il a. Seul un instantane NOUVEAU se voit.
|
||||||
|
procedure FetchAndDecrypt(const AUrl, ATok, APwd: string;
|
||||||
|
ASilent: Boolean = False);
|
||||||
procedure AdoptVault(const APlainJson: string);
|
procedure AdoptVault(const APlainJson: string);
|
||||||
procedure LockVault;
|
procedure LockVault;
|
||||||
|
|
||||||
@@ -202,6 +210,12 @@ begin
|
|||||||
LEvents.SetApplicationEventHandler(HandleAppEvent);
|
LEvents.SetApplicationEventHandler(HandleAppEvent);
|
||||||
|
|
||||||
ShowUnlock;
|
ShowUnlock;
|
||||||
|
|
||||||
|
// Ouverture automatique du coffre local. Differee apres la construction :
|
||||||
|
// l'invite biometrique s'afficherait sinon avant la premiere peinture de la
|
||||||
|
// fenetre, sur un fond vide.
|
||||||
|
if HasVault then
|
||||||
|
TThread.ForceQueue(nil, procedure begin DoOpenLocal(nil); end);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TForm8.Destroy;
|
destructor TForm8.Destroy;
|
||||||
@@ -635,18 +649,31 @@ begin
|
|||||||
FVault.LoadFromJson(APlainJson);
|
FVault.LoadFromJson(APlainJson);
|
||||||
Log(' ' + FVault.LiveCount.ToString + ' entrees, ' +
|
Log(' ' + FVault.LiveCount.ToString + ' entrees, ' +
|
||||||
FVault.TrashCount.ToString + ' en corbeille');
|
FVault.TrashCount.ToString + ' en corbeille');
|
||||||
|
// Deja dans l'application : reconstruire la liste SANS y ramener
|
||||||
|
// l'utilisateur. Obligatoire meme s'il est dans le detail - les lignes de
|
||||||
|
// la liste portent des indices vers l'ancien coffre, et un appui ouvrirait
|
||||||
|
// la mauvaise entree.
|
||||||
|
if FLayList.Visible or FLayDetail.Visible then
|
||||||
|
OnSearchChanged(nil)
|
||||||
|
else
|
||||||
ShowList;
|
ShowList;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TForm8.OpenLocalNow;
|
procedure TForm8.OpenLocalNow;
|
||||||
var
|
var
|
||||||
LPlain, LETag: string;
|
LPlain, LETag, LPwd: string;
|
||||||
begin
|
begin
|
||||||
if LoadVault(LPlain, LETag) then
|
if LoadVault(LPlain, LETag, LPwd) then
|
||||||
begin
|
begin
|
||||||
FETag := LETag;
|
FETag := LETag;
|
||||||
|
if LPwd <> '' then FSyncPwd := LPwd;
|
||||||
try
|
try
|
||||||
AdoptVault(LPlain);
|
AdoptVault(LPlain);
|
||||||
|
// Afficher d'abord, synchroniser ensuite : le coffre est a l'ecran, le
|
||||||
|
// reseau se debrouille derriere. Sans mot de passe range, on ne peut
|
||||||
|
// rien ouvrir de nouveau - inutile d'aller voir.
|
||||||
|
if FSyncPwd <> '' then
|
||||||
|
FetchAndDecrypt(FUrl.Text.Trim, FToken.Text.Trim, FSyncPwd, True);
|
||||||
except
|
except
|
||||||
on E: Exception do
|
on E: Exception do
|
||||||
begin
|
begin
|
||||||
@@ -705,7 +732,10 @@ begin
|
|||||||
// thread de travail est un plantage differe, pas une erreur de compilation.
|
// thread de travail est un plantage differe, pas une erreur de compilation.
|
||||||
LUrl := FUrl.Text.Trim;
|
LUrl := FUrl.Text.Trim;
|
||||||
LTok := FToken.Text.Trim;
|
LTok := FToken.Text.Trim;
|
||||||
|
// Ce qui est tape l'emporte : c'est ainsi qu'on corrige un mot de passe
|
||||||
|
// range qui ne convient plus.
|
||||||
LPwd := FPwd.Text;
|
LPwd := FPwd.Text;
|
||||||
|
if LPwd = '' then LPwd := FSyncPwd;
|
||||||
if LPwd = '' then
|
if LPwd = '' then
|
||||||
begin
|
begin
|
||||||
Status('Mot de passe de sync requis');
|
Status('Mot de passe de sync requis');
|
||||||
@@ -715,21 +745,22 @@ begin
|
|||||||
FetchAndDecrypt(LUrl, LTok, LPwd);
|
FetchAndDecrypt(LUrl, LTok, LPwd);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TForm8.FetchAndDecrypt(const AUrl, ATok, APwd: string);
|
procedure TForm8.FetchAndDecrypt(const AUrl, ATok, APwd: string;
|
||||||
|
ASilent: Boolean);
|
||||||
begin
|
begin
|
||||||
SetBusy(True);
|
SetBusy(True);
|
||||||
Status('Telechargement...');
|
if not ASilent then Status('Telechargement...');
|
||||||
TThread.CreateAnonymousThread(
|
TThread.CreateAnonymousThread(
|
||||||
procedure
|
procedure
|
||||||
var
|
var
|
||||||
LClient: TSyncClient;
|
LClient: TSyncClient;
|
||||||
LRes: TSyncResult;
|
LRes: TSyncResult;
|
||||||
LPlain, LCached, LCachedETag: string;
|
LPlain, LCached, LCachedETag, LCachedPwd: string;
|
||||||
LSw: TStopwatch;
|
LSw: TStopwatch;
|
||||||
begin
|
begin
|
||||||
// Le coffre local d'abord : s'il est la, on connait deja l'ETag et on
|
// Le coffre local d'abord : s'il est la, on connait deja l'ETag et on
|
||||||
// evite les 4 secondes de derivation quand rien n'a change.
|
// evite les 4 secondes de derivation quand rien n'a change.
|
||||||
if (FETag = '') and LoadVault(LCached, LCachedETag) then
|
if (FETag = '') and LoadVault(LCached, LCachedETag, LCachedPwd) then
|
||||||
FETag := LCachedETag;
|
FETag := LCachedETag;
|
||||||
|
|
||||||
LClient := TSyncClient.Create(AUrl, ATok);
|
LClient := TSyncClient.Create(AUrl, ATok);
|
||||||
@@ -760,10 +791,11 @@ begin
|
|||||||
procedure
|
procedure
|
||||||
begin
|
begin
|
||||||
if FVault.Count > 0 then
|
if FVault.Count > 0 then
|
||||||
begin
|
// Rien a faire : ce qui est affiche est deja a jour. En
|
||||||
Log(' 304 : inchange, coffre deja ouvert');
|
// rafraichissement de fond c'est le cas courant, et il
|
||||||
ShowList;
|
// doit passer inapercu - surtout pas de retour a la liste
|
||||||
end
|
// alors que l'utilisateur consulte une entree.
|
||||||
|
Log(' 304 : inchange, coffre deja ouvert')
|
||||||
else if LCached <> '' then
|
else if LCached <> '' then
|
||||||
begin
|
begin
|
||||||
Log(' 304 : inchange, coffre servi depuis le cache');
|
Log(' 304 : inchange, coffre servi depuis le cache');
|
||||||
@@ -778,6 +810,7 @@ begin
|
|||||||
// Un ETag sans clair correspondant : l'invariant est rompu.
|
// Un ETag sans clair correspondant : l'invariant est rompu.
|
||||||
// On le jette pour que l'appel suivant retelecharge.
|
// On le jette pour que l'appel suivant retelecharge.
|
||||||
FETag := '';
|
FETag := '';
|
||||||
|
if not ASilent then
|
||||||
Status('Cache absent - appuyer a nouveau pour telecharger');
|
Status('Cache absent - appuyer a nouveau pour telecharger');
|
||||||
end;
|
end;
|
||||||
end);
|
end);
|
||||||
@@ -787,13 +820,18 @@ begin
|
|||||||
begin
|
begin
|
||||||
// Le serveur repond pareil dans les deux cas, par conception.
|
// Le serveur repond pareil dans les deux cas, par conception.
|
||||||
Log(' 404 : pas d''instantane OU jeton invalide');
|
Log(' 404 : pas d''instantane OU jeton invalide');
|
||||||
|
if not ASilent then
|
||||||
TThread.Queue(nil, procedure
|
TThread.Queue(nil, procedure
|
||||||
begin Status('Rien a telecharger (404)'); end);
|
begin Status('Rien a telecharger (404)'); end);
|
||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
ssRefused, ssHttpError, ssNetworkError:
|
ssRefused, ssHttpError, ssNetworkError:
|
||||||
begin
|
begin
|
||||||
|
// En fond, un echec reseau ne se signale pas : le coffre local
|
||||||
|
// est affiche, hors ligne est un etat normal, et une alerte ici
|
||||||
|
// apprendrait a l'utilisateur a ignorer les alertes.
|
||||||
Log(' echec : ' + LRes.Error);
|
Log(' echec : ' + LRes.Error);
|
||||||
|
if not ASilent then
|
||||||
TThread.Queue(nil, procedure
|
TThread.Queue(nil, procedure
|
||||||
begin Status('Echec reseau'); end);
|
begin Status('Echec reseau'); end);
|
||||||
Exit;
|
Exit;
|
||||||
@@ -801,6 +839,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
Log(' recu ' + Length(LRes.Container).ToString + ' octets');
|
Log(' recu ' + Length(LRes.Container).ToString + ' octets');
|
||||||
|
if not ASilent then
|
||||||
TThread.Queue(nil, procedure begin Status('Dechiffrement...'); end);
|
TThread.Queue(nil, procedure begin Status('Dechiffrement...'); end);
|
||||||
|
|
||||||
LSw := TStopwatch.StartNew;
|
LSw := TStopwatch.StartNew;
|
||||||
@@ -817,7 +856,9 @@ begin
|
|||||||
// True : on DEMANDE la protection par authentification. PMA.Store
|
// True : on DEMANDE la protection par authentification. PMA.Store
|
||||||
// retombe tout seul sur une cle simple si l'appareil n'a ni
|
// retombe tout seul sur une cle simple si l'appareil n'a ni
|
||||||
// empreinte ni code, plutot que de renoncer au cache.
|
// empreinte ni code, plutot que de renoncer au cache.
|
||||||
SaveVault(LPlain, FETag, True);
|
// Le mot de passe part avec le coffre : c'est lui qui permettra au
|
||||||
|
// prochain lancement de rafraichir sans rien demander.
|
||||||
|
SaveVault(LPlain, FETag, APwd, True);
|
||||||
if VaultNeedsAuth then
|
if VaultNeedsAuth then
|
||||||
Log(' cache ecrit - protege par biometrie/code')
|
Log(' cache ecrit - protege par biometrie/code')
|
||||||
else
|
else
|
||||||
@@ -832,10 +873,13 @@ begin
|
|||||||
TThread.Queue(nil,
|
TThread.Queue(nil,
|
||||||
procedure
|
procedure
|
||||||
begin
|
begin
|
||||||
|
FSyncPwd := APwd; // il vient d'ouvrir un conteneur : il est bon
|
||||||
try
|
try
|
||||||
AdoptVault(LPlain);
|
AdoptVault(LPlain);
|
||||||
except
|
except
|
||||||
on E: Exception do Status('Instantane illisible : ' + E.Message);
|
on E: Exception do
|
||||||
|
if not ASilent then
|
||||||
|
Status('Instantane illisible : ' + E.Message);
|
||||||
end;
|
end;
|
||||||
end);
|
end);
|
||||||
except
|
except
|
||||||
@@ -844,6 +888,12 @@ begin
|
|||||||
Log('ERREUR ' + E.ClassName + ' : ' + E.Message);
|
Log('ERREUR ' + E.ClassName + ' : ' + E.Message);
|
||||||
// Le cas de loin le plus frequent, et le message par defaut ne le
|
// Le cas de loin le plus frequent, et le message par defaut ne le
|
||||||
// dit pas : GCM echoue a la verification quand la cle est fausse.
|
// dit pas : GCM echoue a la verification quand la cle est fausse.
|
||||||
|
//
|
||||||
|
// En fond, cela veut dire que le mot de passe range ne convient
|
||||||
|
// plus - le poste a change de mot de passe de sync. On ne le jette
|
||||||
|
// PAS : il faudra le retaper, mais garder l'ancien laisse au moins
|
||||||
|
// le champ prerempli, et le coffre local reste consultable.
|
||||||
|
if not ASilent then
|
||||||
TThread.Queue(nil, procedure
|
TThread.Queue(nil, procedure
|
||||||
begin Status('Echec - mot de passe de sync incorrect ?'); end);
|
begin Status('Echec - mot de passe de sync incorrect ?'); end);
|
||||||
end;
|
end;
|
||||||
|
|||||||
Reference in New Issue
Block a user