diff --git a/android-client/web/app.html b/android-client/web/app.html
index 4a8c53f..e4c632b 100644
--- a/android-client/web/app.html
+++ b/android-client/web/app.html
@@ -395,7 +395,11 @@
×
@@ -535,12 +539,15 @@
×
- The master password never leaves this device. It is what
- decrypts the vault; the token only opens the repository.
+ The sync password never leaves this device. It is what
+ encrypts the copy kept in the repository, so it must be the same on every
+ device that shares it; the token only opens the repository. It is not the
+ password that opens a vault created on this phone - that one is asked for
+ on the home screen.
Unlock code
diff --git a/mainApk.pas b/mainApk.pas
index 8a3f43f..3c17307 100644
--- a/mainApk.pas
+++ b/mainApk.pas
@@ -134,6 +134,17 @@ type
// rafraichissement de fond silencieux : sans lui, chaque modification
// faite sur le poste ferait apparaitre une invite au lancement.
FSyncPwd: string;
+ /// LE MOT DE PASSE DU COFFRE LOCAL, et lui seul.
+ ///
+ /// Il ouvre `vault-local.json` - un coffre ne sur ce telephone et pas
+ /// encore publie. Il n'a RIEN a voir avec le secret du depot, meme si
+ /// l'utilisateur choisit la meme valeur pour les deux : ce sont deux roles,
+ /// et les confondre faisait qu'un coffre cree ici pretendait sceller le
+ /// depot avec son propre mot de passe.
+ ///
+ /// Vide des que le conteneur local disparait - c'est-a-dire des que la
+ /// reconciliation a passe l'autorite au depot.
+ FVaultPwd: string;
/// Coordonnees du serveur. Delphi en est le detenteur ; la page ne fait
/// que les editer et les lui renvoyer quand un champ est quitte.
@@ -895,9 +906,20 @@ begin
RefuseChange('Busy - wait for the current operation');
Exit;
end;
- if FSyncPwd = '' then
+ // DEUX SECRETS, DEUX EXIGENCES. Un coffre ne ici n'ecrit que son conteneur
+ // local et n'a donc pas besoin du secret du depot ; un coffre publie n'a pas
+ // de conteneur local et n'a donc pas besoin du sien.
+ if HasLocalContainer then
begin
- RefuseChange('Master password missing - open the vault first');
+ if FVaultPwd = '' then
+ begin
+ RefuseChange('Vault password missing - open the vault first');
+ Exit;
+ end;
+ end
+ else if FSyncPwd = '' then
+ begin
+ RefuseChange('Sync password missing - open the vault first');
Exit;
end;
SetBusy(True);
@@ -929,7 +951,7 @@ begin
// donc le cache avant toute chose, et le depot suit quand il peut.
// ---------------------------------------------------------------
LSw := TStopwatch.StartNew;
- if LLocalOnly then LPlain := OpenContainer(LoadLocalContainer, FSyncPwd)
+ if LLocalOnly then LPlain := OpenContainer(LoadLocalContainer, FVaultPwd)
else LPlain := FPlain;
if LPlain = '' then
raise Exception.Create('no snapshot in hand - open the vault again');
@@ -1225,11 +1247,23 @@ begin
Status('No local vault to reconcile');
Exit;
end;
- if FSyncPwd = '' then
+ // LES DEUX SONT REQUIS ICI, ET NULLE PART AILLEURS : c'est le seul moment ou
+ // le conteneur local et l'instantane du depot se rencontrent.
+ if FVaultPwd = '' then
begin
Status('Open the vault first');
Exit;
end;
+ // CE QUI EST DANS LES REGLAGES FAIT FOI quand le coffre n'en porte pas encore.
+ // Un coffre ne ici n'a jamais vu le depot : son cache ne contient donc aucun
+ // secret de sync, et c'est le champ des reglages qui le donne. Meme
+ // precedence que DoSync, pour que les deux ne divergent pas.
+ if FSyncPwd = '' then FSyncPwd := FPwd;
+ if FSyncPwd = '' then
+ begin
+ Status('Set the sync password in Settings');
+ Exit;
+ end;
SetBusy(True);
Status('Reconciling...');
@@ -1248,7 +1282,17 @@ begin
LErr := '';
try
try
- LLocal := OpenContainer(LoadLocalContainer, FSyncPwd);
+ // 1. LE COFFRE LOCAL, sous SON mot de passe.
+ LLocal := OpenContainer(LoadLocalContainer, FVaultPwd);
+
+ // 2. ON JETTE LA CLE QUI VIENT DE SERVIR. Elle appartient au conteneur
+ // local ; tout ce qui suit concerne le depot, scelle par un autre
+ // secret. La garder ferait resceller le depot sous le mot de passe du
+ // coffre local - c'est exactement la confusion qu'on defait ici, et
+ // elle rendrait l'instantane illisible pour le poste.
+ FKey := nil;
+ FKeySalt := nil;
+ FKeyIters := 0;
for LAttempt := 1 to 3 do
begin
@@ -1268,6 +1312,8 @@ begin
end
else if LGet.Status = ssOK then
begin
+ // Ouvrir le distant pose la cle DU DEPOT dans FKey : c'est elle
+ // qui servira a le resceller quelques lignes plus bas.
LRemote := OpenContainer(LGet.Container, FSyncPwd);
LMerged := MergeSnapshots(LLocal, LRemote);
end
@@ -1277,7 +1323,11 @@ begin
Break;
end;
- LBody := EncryptContainerWithKey(LMerged, FKey, FKeySalt, FKeyIters);
+ // Depot vide : aucune cle n'a ete tiree de lui, il faut donc la
+ // deriver du mot de passe de sync. C'est le seul chemin qui paie les
+ // quelques secondes, et il n'arrive qu'une fois.
+ if FKey = nil then LBody := EncryptContainer(LMerged, FSyncPwd)
+ else LBody := EncryptContainerWithKey(LMerged, FKey, FKeySalt, FKeyIters);
LPut := LClient.Put(LBody, LGet.ETag, 'reconciled from phone');
if LPut.Status = ssOK then
begin
@@ -1298,7 +1348,11 @@ begin
// PUBLIE, DONC PLUS BESOIN DU CONTENEUR LOCAL. C'est ce geste qui
// passe l'autorite au depot ; le faire avant la publication aurait
// perdu le coffre.
+ // Le conteneur local n'existe plus : son mot de passe non plus.
+ // L'autorite est passee au depot, et c'est le secret de sync qui
+ // commande desormais.
DropLocalContainer;
+ FVaultPwd := '';
try
SaveVault(LMerged, FETag, FSyncPwd, BiometricAvailable, False,
FPinSealed, FKey, FKeySalt, FKeyIters);
@@ -1747,6 +1801,9 @@ begin
FKeyIters := 0;
FPlain := '';
FHistory := nil;
+ // Le mot de passe du coffre local part avec le clair : le garder ouvrirait
+ // le conteneur sans rien demander.
+ FVaultPwd := '';
// Le code aussi : le retenir apres un verrouillage reviendrait a ne pas
// verrouiller. Le garde de SaveVault protege le cache d'ici la.
FPinSealed := '';
@@ -1827,19 +1884,12 @@ begin
begin
SetBusy(False);
FUser := AUser;
- FSyncPwd := APwd;
- // LE COFFRE QUI VIENT DE S'OUVRIR DIT LE MOT DE PASSE DE SYNC.
- //
- // Sans cette ligne, FPwd gardait la valeur de premier lancement -
- // en debogage, une constante ; en release, du vide - et les
- // reglages affichaient donc un mot de passe qui n'etait pas celui
- // du coffre detenu. Pire, DoSync la PREFERE a celle du coffre au
- // nom de "ce qui est tape l'emporte" : or rien n'avait ete tape.
- // Les deux chemins de synchronisation travaillaient ainsi avec
- // deux mots de passe differents sur le meme coffre.
- FPwd := APwd;
- WebCall(Format('PM.setConfig(%s, %s, %s, false)',
- [JsArg(FUrl), JsArg(FToken), JsArg(FPwd)]));
+ // CE MOT DE PASSE NE TOUCHE PAS AU DEPOT. Il scelle le conteneur
+ // local, rien d'autre. Le secret du depot vit dans les reglages et
+ // doit etre le meme sur tous les appareils - le remplacer par
+ // celui-ci ferait publier un instantane que le poste ne saurait
+ // plus ouvrir.
+ FVaultPwd := APwd;
Log('Vault created locally for ' + AUser);
AdoptVault(LPlain);
end);
@@ -1887,6 +1937,7 @@ begin
LDoc: TJSONObject;
begin
try
+ FVaultPwd := APwd; // avant l'ouverture : c'est lui qui la fait
LPlain := OpenContainer(LoadLocalContainer, APwd);
LOwner := '';
LDoc := TJSONObject.ParseJSONValue(LPlain) as TJSONObject;
@@ -1910,19 +1961,9 @@ begin
begin
SetBusy(False);
if LOwner <> '' then FUser := LOwner else FUser := AUser;
- FSyncPwd := APwd;
- // LE COFFRE QUI VIENT DE S'OUVRIR DIT LE MOT DE PASSE DE SYNC.
- //
- // Sans cette ligne, FPwd gardait la valeur de premier lancement -
- // en debogage, une constante ; en release, du vide - et les
- // reglages affichaient donc un mot de passe qui n'etait pas celui
- // du coffre detenu. Pire, DoSync la PREFERE a celle du coffre au
- // nom de "ce qui est tape l'emporte" : or rien n'avait ete tape.
- // Les deux chemins de synchronisation travaillaient ainsi avec
- // deux mots de passe differents sur le meme coffre.
- FPwd := APwd;
- WebCall(Format('PM.setConfig(%s, %s, %s, false)',
- [JsArg(FUrl), JsArg(FToken), JsArg(FPwd)]));
+ // Meme regle qu'a la creation : ce mot de passe ouvre le conteneur
+ // local et s'arrete la.
+ FVaultPwd := APwd;
AdoptVault(LPlain);
end);
@@ -2815,7 +2856,9 @@ begin
ClearUnlockCode;
Exit;
end;
- if (FPlain = '') or (FSyncPwd = '') then
+ // Le secret du depot n'entre pas ici : le code scelle le CACHE, et un coffre
+ // ne sur ce telephone n'a pas encore de depot.
+ if FPlain = '' then
begin
WebCall('PM.toast("Open the vault first")');
Exit;
@@ -2855,7 +2898,9 @@ begin
WebCall('PM.toast("No unlock code to remove")');
Exit;
end;
- if (FPlain = '') or (FSyncPwd = '') then
+ // Le secret du depot n'entre pas ici : le code scelle le CACHE, et un coffre
+ // ne sur ce telephone n'a pas encore de depot.
+ if FPlain = '' then
begin
WebCall('PM.toast("Open the vault first")');
Exit;