@@ -227,8 +235,10 @@
clair alors qu'il ouvre le depot : le moins grave des trois secrets
de cet ecran, mais le seul qu'un regard par-dessus l'epaule
attrapait. On le saisit une fois ; le relire n'a aucun usage. -->
+
Gitea token · needs read AND write
+
Sync password · decrypts the vault
diff --git a/mainApk.pas b/mainApk.pas
index 9e5840c..20ca97a 100644
--- a/mainApk.pas
+++ b/mainApk.pas
@@ -32,7 +32,7 @@ interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes,
System.Diagnostics, System.Rtti, System.NetEncoding, System.DateUtils,
- System.Generics.Collections, System.IOUtils,
+ System.Generics.Collections, System.IOUtils, System.Hash,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Platform,
FMX.Controls.Presentation, FMX.StdCtrls, FMX.Memo, FMX.Memo.Types,
FMX.ScrollBox, FMX.Layouts, FMX.Edit, FMX.ListBox, FMX.Objects,
@@ -418,6 +418,14 @@ begin
SetLength(FWebPending, 0);
end;
+/// Empreinte courte d'un secret, pour le journal. On veut savoir LEQUEL des
+/// jetons est en place, jamais sa valeur : huit caracteres de son SHA-256
+/// suffisent a les distinguer et n'en revelent rien.
+function Fingerprint(const ASecret: string): string;
+begin
+ if ASecret = '' then Exit('(vide)');
+ Result := Copy(THashSHA2.GetHashString(ASecret), 1, 8);
+end;
/// Chiffre un petit conteneur, le relit, et le laisse sur le disque prive pour
/// qu'une autre implementation le verifie. Iterations volontairement basses :
/// ce qu'on eprouve ici est le CABLAGE - cle, IV, place du tag - pas le cout
@@ -496,8 +504,8 @@ begin
TTimeZone.Local.ToUniversalTime(Now))]),
FSyncPwd, 1000);
Log('PUT ' + LUrl);
- Log(' token ' + IntToStr(Length(FToken)) + ' chars, body ' +
- IntToStr(Length(LBody)) + ' chars');
+ Log(Format(' token %s (%d chars), body %d chars',
+ [Fingerprint(FToken), Length(FToken), Length(LBody)]));
// Sha vide : on cree le fichier, ou on echoue en 409 s'il existe deja -
// ce qui prouverait le controle de concurrence aussi surement.
LRes := LClient.Put(LBody, '', 'write path probe from phone');
@@ -528,6 +536,8 @@ begin
FUrl := LUrl;
if LToken <> '' then FToken := LToken;
end;
+ Log(Format('config loaded: token %s (%d chars), url %s',
+ [Fingerprint(FToken), Length(FToken), FUrl]));
WebCall(Format('PM.setConfig(%s, %s, %s, %s)',
[JsArg(FUrl), JsArg(FToken), JsArg(FPwd),
// Replier des champs vides revient a cacher la seule chose a faire.
@@ -560,7 +570,16 @@ end;
procedure TForm8.OnWebNavigate(ASender: TObject; const AUrl: string);
begin
// Le moteur navigue aussi pour charger la page elle-meme.
- if AUrl.StartsWith('cmd://') then HandleWebCommand(AUrl.Substring(6));
+ // L'ACTION SEULE, jamais la requete : elle porte le jeton et le mot de passe.
+ // Sans cette trace on ne peut pas distinguer « la commande n'arrive pas » de
+ // « elle arrive et ne fait rien », et les deux se ressemblent de l'exterieur.
+ if AUrl.StartsWith('cmd://') then
+ begin
+ var LDbg := AUrl.Substring(6);
+ if LDbg.Contains('?') then LDbg := LDbg.Substring(0, LDbg.IndexOf('?')) + '?...';
+ Log('cmd ' + LDbg);
+ HandleWebCommand(AUrl.Substring(6));
+ end;
end;
procedure TForm8.HandleWebCommand(const AUrl: string);
@@ -613,6 +632,11 @@ begin
FUrl := TNetEncoding.URL.Decode(Param('u')).Trim;
FToken := TNetEncoding.URL.Decode(Param('t')).Trim;
FPwd := TNetEncoding.URL.Decode(Param('p'));
+ // L'empreinte du mot de passe AUSSI : si une saisie destinee au jeton
+ // atterrit dans le champ voisin - les deux sont masques - c'est celle-ci
+ // qui bouge, et le jeton reste inchange sans que rien ne l'explique.
+ Log(Format('config from page: token %s, pwd %s',
+ [Fingerprint(FToken), Fingerprint(FPwd)]));
end
else if LAction = 'openvault' then
@@ -678,7 +702,10 @@ begin
// Les lignes du detail portent des valeurs EN CLAIR (FRows) : les detruire
// fait partie du verrouillage, pas de l'affichage.
FCurrent := Default(TVaultEntry);
- PushConfig;
+ // PAS DE PushConfig HORS DEMARRAGE. Redescendre les coordonnees du serveur
+ // ecrase ce que l'utilisateur vient de taper - l'auto-verrouillage le faisait
+ // donc sans le moindre geste de sa part, et le champ jeton semblait ne rien
+ // retenir. Verrouiller efface le clair ; la configuration n'a rien a y voir.
ShowUnlock;
end;
@@ -775,7 +802,6 @@ begin
// Un coffre local illisible se remplace, il ne se repare pas.
Log('Local vault corrupt: ' + E.Message);
ClearVault;
- PushConfig;
ShowUnlock;
end;
end;
@@ -785,7 +811,6 @@ begin
// ShowUnlock AVANT le message : il repositionne le statut selon ce que
// l'appareil detient, et ecraserait donc l'explication.
FVaultUnreadable := True;
- PushConfig;
ShowUnlock;
Log('Local vault unreadable: ' + LastStoreError);
Status('Local vault unreadable - see log');
@@ -841,7 +866,6 @@ begin
FVaultUnreadable := True;
Log('No usable protection on this device - vault kept but unreadable');
Log(' ' + LastBiometricError);
- PushConfig;
ShowUnlock;
Status('Screen lock missing - download again to replace the cache');
end;