feat(android): deux secrets separes, comme sur le poste
Le mot de passe de creation scellait le conteneur local ET pretendait sceller l'instantane du depot. Un coffre cree ici publiait donc sous son propre mot de passe, que le poste ne savait plus ouvrir - et le rafraichissement echouait avec "wrong password" sur un depot pourtant intact. FVaultPwd ouvre le conteneur local et s'arrete la. Le secret du depot vit dans les reglages, doit etre le meme sur tous les appareils, et c'est lui seul qui ouvre et rescelle l'instantane. Les deux ne se rencontrent qu'a UN endroit, la reconciliation : le conteneur local s'ouvre sous le sien, puis la cle est jetee avant de toucher au depot - la garder rescellerait le depot sous le mauvais secret. Ailleurs ils ne se croisent jamais : un coffre ne ici ne publie pas, un coffre publie n'a plus de conteneur local. Migration : rien a rechiffrer. Les coffres existants ont simplement les deux valeurs egales, et cessent d'etre forces de le rester. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -395,7 +395,11 @@
|
||||
<div class="in-x" data-clear="user">×</div>
|
||||
</div>
|
||||
<div class="in-wrap">
|
||||
<input class="field-in" id="pass" placeholder="master password"
|
||||
<!-- DEUX SECRETS, DEUX NOMS. Celui-ci ouvre le coffre garde sur cet
|
||||
appareil. Il s'appelait "master password" et servait aussi de
|
||||
secret du depot - un coffre cree ici pretendait alors sceller le
|
||||
depot avec lui, que le poste ne savait plus ouvrir. -->
|
||||
<input class="field-in" id="pass" placeholder="vault password"
|
||||
type="password" autocomplete="off">
|
||||
<div class="in-x" data-clear="pass">×</div>
|
||||
</div>
|
||||
@@ -535,12 +539,15 @@
|
||||
<div class="in-x" data-clear="sTok">×</div>
|
||||
</div>
|
||||
<div class="in-wrap">
|
||||
<input class="field-in" id="sPwd" placeholder="master password"
|
||||
<input class="field-in" id="sPwd" placeholder="sync password"
|
||||
type="password" autocomplete="off">
|
||||
<div class="in-x" data-clear="sPwd">×</div>
|
||||
</div>
|
||||
<div class="note">The master password never leaves this device. It is what
|
||||
decrypts the vault; the token only opens the repository.</div>
|
||||
<div class="note">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.</div>
|
||||
|
||||
<h2>Unlock code</h2>
|
||||
<div class="in-wrap">
|
||||
|
||||
+79
-34
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user