fix(android): poser, changer et retirer le code exigent un coffre ouvert
Deux branches de l'ouverture posaient le code a partir de ce qui trainait dans les champs. La premiere appliquait un "nouveau code" depose par les reglages. Elle n'exigeait rien de celui qui le deposait : n'importe qui tenant le telephone deverrouille pouvait en poser un, et c'est le proprietaire qui, en ouvrant son coffre, l'appliquait contre lui-meme. La seconde rescellait sous le code tape des que le cache ne l'etait plus, ce qui DEFAISAIT LE RETRAIT : on retirait le code, le champ le portait encore, et l'ouverture suivante le reposait sans qu'un mot le dise. Le premier octet du cache le disait - VER_PIN apres un retrait annonce reussi. Poser et changer passent maintenant par SetUnlockCode, jumeau de ClearUnlockCode : geste explicite, coffre deja ouvert - donc code courant connu - et effet immediat. Le champ de l'accueil ne veut plus dire qu'une chose, "ouvre avec ceci", et ne parait que lorsqu'un code est pose. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+25
-33
@@ -402,22 +402,6 @@
|
||||
type="password" inputmode="numeric" autocomplete="off">
|
||||
<div class="in-x" data-clear="pin">×</div>
|
||||
</div>
|
||||
<!-- CHANGER LE CODE demande de connaitre l'actuel : le champ du dessus
|
||||
doit ouvrir le coffre pour que celui-ci prenne effet. Sans cette
|
||||
regle, toute ecriture du cache rescellait sous ce qui trainait dans
|
||||
le champ - une synchronisation, qui ne demande pourtant aucun code,
|
||||
suffisait a le changer sans qu'un mot le dise.
|
||||
|
||||
PLUS JAMAIS MONTRE. Les reglages posent et changent le code, et ce
|
||||
champ y faisait doublon sur l'ecran ou l'on veut seulement ouvrir.
|
||||
Il RESTE dans la page, cache : c'est lui que "Set this code" remplit
|
||||
avant pushConfig, donc il porte toujours la valeur - il ne la
|
||||
demande plus. -->
|
||||
<div class="in-wrap" id="pin2wrap" hidden>
|
||||
<input class="field-in" id="pin2" placeholder="new unlock code"
|
||||
type="password" inputmode="numeric" autocomplete="off">
|
||||
<div class="in-x" data-clear="pin2">×</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- UNE CROIX PAR CHAMP. Vider par la touche retour demande une quarantaine
|
||||
d'appuis sur un jeton, et laisse facilement un caractere - ce qui donne
|
||||
@@ -634,10 +618,9 @@ function pushConfig() {
|
||||
send('cfg?u=' + encodeURIComponent(elUrl.value.trim())
|
||||
+ '&t=' + encodeURIComponent(elTok.value.trim())
|
||||
+ '&p=' + encodeURIComponent(elPwd.value)
|
||||
+ '&c=' + encodeURIComponent(elPin.value)
|
||||
+ '&c2=' + encodeURIComponent(document.getElementById('pin2').value));
|
||||
+ '&c=' + encodeURIComponent(elPin.value));
|
||||
}
|
||||
[elUrl, elTok, elPwd, elPin, document.getElementById('pin2')].forEach(function (el) {
|
||||
[elUrl, elTok, elPwd, elPin].forEach(function (el) {
|
||||
el.addEventListener('change', pushConfig);
|
||||
el.addEventListener('blur', pushConfig);
|
||||
});
|
||||
@@ -645,6 +628,18 @@ function pushConfig() {
|
||||
// Le meme bouton dans les deux sens : creer un coffre et en ouvrir un ne
|
||||
// different que par ce qui existe deja sur l'appareil, et Delphi le sait.
|
||||
var authMode = 'open';
|
||||
// LE CHAMP DU CODE NE SERT PLUS QU'A OUVRIR, donc il ne parait que lorsqu'un
|
||||
// code est reellement pose. Il proposait aussi d'en poser un, et c'est ce
|
||||
// double sens qui defaisait les retraits : le champ gardait une valeur, et la
|
||||
// prochaine ouverture rescellait sous elle. On pose un code dans les reglages.
|
||||
//
|
||||
// DEUX ECRIVAINS, UNE SEULE REGLE : Delphi annonce l'un puis l'autre, et le
|
||||
// dernier ecrasait le premier. Chacun met a jour sa variable, la fonction
|
||||
// tranche.
|
||||
var pinNeeded = false;
|
||||
function syncPinbox() {
|
||||
document.getElementById('pinbox').hidden = !pinNeeded || (authMode !== 'open');
|
||||
}
|
||||
document.getElementById('btnAuth').addEventListener('click', function () {
|
||||
var u = document.getElementById('user').value.trim();
|
||||
var p = document.getElementById('pass').value;
|
||||
@@ -1489,12 +1484,11 @@ document.getElementById('sLog').addEventListener('click', function () {
|
||||
document.getElementById('sPinSet').addEventListener('click', function () {
|
||||
var v = document.getElementById('sPinNew').value;
|
||||
if (!v) { toast('Type a code first'); return; }
|
||||
// LE MEME CHEMIN QUE L'ACCUEIL : c'est l'ouverture du coffre qui pose ou
|
||||
// change le sceau, et elle seule. Ici on ne fait que remplir le champ.
|
||||
document.getElementById('pin2').value = v;
|
||||
pushConfig();
|
||||
closeSettings();
|
||||
toast('Open the vault to apply the new code');
|
||||
// DEMANDE EXPLICITE, EFFET IMMEDIAT. Le code ne se depose plus dans un champ
|
||||
// que l'ouverture suivante appliquerait : Delphi refuse si le coffre n'est
|
||||
// pas ouvert, ce qui prouve que le code courant est connu.
|
||||
send('pinset?c=' + encodeURIComponent(v));
|
||||
document.getElementById('sPinNew').value = '';
|
||||
});
|
||||
document.getElementById('sPinClear').addEventListener('click', function (ev) {
|
||||
var b = ev.currentTarget;
|
||||
@@ -1632,22 +1626,20 @@ var PM = {
|
||||
authMode = mode;
|
||||
var box = document.getElementById('authbox');
|
||||
box.hidden = (mode === 'open');
|
||||
document.getElementById('pinbox').hidden = (mode !== 'open');
|
||||
syncPinbox();
|
||||
document.getElementById('btnAuth').textContent =
|
||||
(mode === 'register') ? 'Create vault' : 'Sign in';
|
||||
},
|
||||
|
||||
setPinNeeded: function (on) {
|
||||
document.getElementById('pin').placeholder =
|
||||
on ? 'unlock code' : 'set an unlock code (optional)';
|
||||
// pin2wrap n'est plus deplie : le champ du nouveau code vit dans les
|
||||
// reglages, celui-ci n'en est que le porteur.
|
||||
pinNeeded = on;
|
||||
syncPinbox();
|
||||
},
|
||||
/// Le code vient d'etre change : le champ du nouveau n'a plus rien a dire,
|
||||
/// et le laisser rempli le reproposerait a chaque ouverture.
|
||||
/// Le code vient de changer : le champ d'ouverture n'a plus rien a dire, et
|
||||
/// le laisser rempli rescellerait sous lui a la prochaine ecriture.
|
||||
pinChanged: function () {
|
||||
document.getElementById('pin2').value = '';
|
||||
document.getElementById('pin').value = '';
|
||||
pushConfig();
|
||||
},
|
||||
focusPin: function () { document.getElementById('pin').focus(); },
|
||||
log: function (line) {
|
||||
|
||||
+70
-36
@@ -201,8 +201,7 @@ type
|
||||
/// Seule l'ouverture du coffre y touche desormais - c'est le seul moment ou
|
||||
/// l'on sait que l'utilisateur connait le code courant.
|
||||
FPinSealed: string;
|
||||
/// Le NOUVEAU code demande, quand on veut en changer. Vide sinon.
|
||||
FPinNew: string;
|
||||
|
||||
|
||||
// --- l'interface entiere, rendue par le moteur du systeme
|
||||
FLayWeb: TLayout;
|
||||
@@ -315,6 +314,10 @@ type
|
||||
/// Retire le code de deverrouillage : le cache se rescelle sous la seule
|
||||
/// cle de l'appareil. Exige un coffre ouvert.
|
||||
procedure ClearUnlockCode;
|
||||
/// Pose ou change le code de deverrouillage. Exige un coffre ouvert, donc
|
||||
/// le code courant deja connu - c'est ce qui empeche un tiers d'en poser un
|
||||
/// que le proprietaire ne connaitrait pas.
|
||||
procedure SetUnlockCode(const ANew: string);
|
||||
/// Va chercher l'icone du site de l'entree ouverte, ou l'efface.
|
||||
procedure SetEntryIcon(AFetch: Boolean);
|
||||
/// Envoie a la page les anciens mots de passe de l'entree ouverte.
|
||||
@@ -1605,7 +1608,6 @@ begin
|
||||
FToken := TNetEncoding.URL.Decode(Param('t')).Trim;
|
||||
FPwd := TNetEncoding.URL.Decode(Param('p'));
|
||||
FPin := TNetEncoding.URL.Decode(Param('c'));
|
||||
FPinNew := TNetEncoding.URL.Decode(Param('c2'));
|
||||
// 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.
|
||||
@@ -1659,6 +1661,9 @@ begin
|
||||
else if LAction = 'icon' then
|
||||
SetEntryIcon(Param('a') = 'fetch')
|
||||
|
||||
else if LAction = 'pinset' then
|
||||
SetUnlockCode(TNetEncoding.URL.Decode(Param('c')))
|
||||
|
||||
else if LAction = 'pinclear' then
|
||||
ClearUnlockCode
|
||||
|
||||
@@ -1963,38 +1968,21 @@ begin
|
||||
// avait pas. C'est la seule certitude de ce genre dans toute l'application.
|
||||
if VaultNeedsPin then FPinSealed := FPin;
|
||||
|
||||
// CHANGER LE CODE - ici, et ici seulement. Il faut avoir ouvert le coffre,
|
||||
// donc connaitre le code courant : sans cela une frappe distraite suffirait
|
||||
// a rendre le cache inouvrable pour son proprietaire.
|
||||
if (FPinNew <> '') and (FPinNew <> FPinSealed) then
|
||||
begin
|
||||
try
|
||||
SaveVault(LPlain, LETag, LPwd, False, False, FPinNew,
|
||||
FKey, FKeySalt, FKeyIters);
|
||||
FPinSealed := FPinNew;
|
||||
FPinNew := '';
|
||||
Log('Unlock code changed');
|
||||
WebCall('PM.toast("Unlock code changed")');
|
||||
WebCall('PM.pinChanged()');
|
||||
except
|
||||
on E: Exception do Log('Unlock code not changed: ' + E.Message);
|
||||
end;
|
||||
end
|
||||
else if (FPin <> '') and (not VaultNeedsPin) then
|
||||
begin
|
||||
try
|
||||
SaveVault(LPlain, LETag, LPwd, False, False, FPin,
|
||||
FKey, FKeySalt, FKeyIters);
|
||||
FPinSealed := FPin;
|
||||
if VaultNeedsPin then
|
||||
Log('Cache re-sealed under the unlock code')
|
||||
else
|
||||
Log('Re-seal under code refused: ' + LastStoreError);
|
||||
except
|
||||
on E: Exception do Log('Re-seal under code failed: ' + E.Message);
|
||||
end;
|
||||
end
|
||||
else if (not VaultNeedsAuth) and (not VaultNeedsPin) and BiometricAvailable then
|
||||
// PLUS RIEN NE POSE NI NE CHANGE LE CODE ICI.
|
||||
//
|
||||
// Deux branches le faisaient, a partir de ce qui trainait dans les champs :
|
||||
// l'une appliquait un "nouveau code" depose par les reglages, l'autre
|
||||
// rescellait sous le code tape des que le cache ne l'etait plus. La seconde
|
||||
// DEFAISAIT LE RETRAIT : on retirait le code, le champ le portait encore,
|
||||
// et l'ouverture suivante le reposait sans qu'un mot le dise. La premiere
|
||||
// ouvrait pire - n'importe qui pouvait deposer un nouveau code depuis les
|
||||
// reglages sans connaitre l'actuel, et c'est le proprietaire qui, en
|
||||
// ouvrant son coffre, l'appliquait contre lui-meme.
|
||||
//
|
||||
// Poser, changer et retirer passent desormais par SetUnlockCode et
|
||||
// ClearUnlockCode : un geste explicite, coffre deja ouvert, effet immediat.
|
||||
// Le champ de l'accueil ne veut plus dire qu'une chose : "ouvre avec ceci".
|
||||
if (not VaultNeedsAuth) and (not VaultNeedsPin) and BiometricAvailable then
|
||||
begin
|
||||
try
|
||||
// Cle NEUVE, obligatoirement : le changement qui vient de ramener la
|
||||
@@ -2751,6 +2739,53 @@ begin
|
||||
end).Start;
|
||||
end;
|
||||
|
||||
/// POSER OU CHANGER LE CODE, IMMEDIATEMENT ET SUR DEMANDE.
|
||||
///
|
||||
/// Le coffre doit etre ouvert : c'est la seule preuve que le code courant est
|
||||
/// connu, et la seule facon de tenir le clair qu'il faut resceller. Sans cette
|
||||
/// exigence, quiconque tenait le telephone deverrouille pouvait deposer un
|
||||
/// code depuis les reglages - le proprietaire l'appliquait ensuite lui-meme en
|
||||
/// ouvrant son coffre, et se retrouvait dehors.
|
||||
procedure TForm8.SetUnlockCode(const ANew: string);
|
||||
begin
|
||||
if FBusy then Exit;
|
||||
if ANew = '' then
|
||||
begin
|
||||
ClearUnlockCode;
|
||||
Exit;
|
||||
end;
|
||||
if (FPlain = '') or (FSyncPwd = '') then
|
||||
begin
|
||||
WebCall('PM.toast("Open the vault first")');
|
||||
Exit;
|
||||
end;
|
||||
try
|
||||
// ARequireAuth a FAUX : les deux protections s'excluent, un cache scelle
|
||||
// par un code porte VER_PIN et non VER_WRAP.
|
||||
SaveVault(FPlain, FETag, FSyncPwd, False, False, ANew,
|
||||
FKey, FKeySalt, FKeyIters);
|
||||
if not VaultNeedsPin then
|
||||
begin
|
||||
Log('Unlock code not set: ' + LastStoreError);
|
||||
WebCall('PM.toast("Could not set the unlock code")');
|
||||
Exit;
|
||||
end;
|
||||
FPinSealed := ANew;
|
||||
// Le champ de l'accueil est vide : il sert a OUVRIR, et le coffre l'est
|
||||
// deja. Le laisser rempli rescellerait sous lui a la prochaine ecriture.
|
||||
FPin := '';
|
||||
Log('Unlock code set');
|
||||
WebCall('PM.toast("Unlock code set")');
|
||||
WebCall('PM.pinChanged()');
|
||||
except
|
||||
on E: Exception do
|
||||
begin
|
||||
Log('Unlock code not set: ' + E.ClassName + ' - ' + E.Message);
|
||||
WebCall('PM.toast("Could not set the unlock code")');
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TForm8.ClearUnlockCode;
|
||||
begin
|
||||
if FBusy then Exit;
|
||||
@@ -2775,7 +2810,6 @@ begin
|
||||
end;
|
||||
FPinSealed := '';
|
||||
FPin := '';
|
||||
FPinNew := '';
|
||||
Log('Unlock code removed');
|
||||
WebCall('PM.toast("Unlock code removed")');
|
||||
WebCall('PM.pinChanged()');
|
||||
|
||||
Reference in New Issue
Block a user