To remove the code, type the current one above first.
- The code seals the copy kept on this device. It can be
- digits or a full password - a longer one is harder to guess, and it is
- asked for only when the vault opens. Removing it leaves the vault
- readable by anyone holding the phone unlocked.
+
+
+
+
Diagnostics
@@ -1648,14 +1650,49 @@ document.getElementById('histBody').addEventListener('click', function (ev) {
document.getElementById('sLog').addEventListener('click', function () {
showLog(document.getElementById('log').hidden);
});
-document.getElementById('sPinSet').addEventListener('click', function () {
- var v = document.getElementById('sPinNew').value;
- if (!v) { toast('Type a code first'); return; }
- // 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.
+// FACON D'OUVRIR. Delphi dit laquelle est en place (PM.setUnlockMode) ; chaque
+// bouton envoie la commande qui existe deja pour la poser. Revenir au
+// verrouillage d'ecran, c'est retirer le code : il faut donc le code courant.
+var unlockMode = 'none', canDeviceLock = false, hasContainer = false;
+function syncUnlockUi() {
+ ['device', 'code', 'password'].forEach(function (m) {
+ var id = { device: 'sModeDevice', code: 'sModeCode', password: 'sModePwd' }[m];
+ document.getElementById(id).classList.toggle('main', unlockMode === m);
+ });
+ document.getElementById('sModeDevice').disabled = !canDeviceLock;
+ document.getElementById('sModeNote').textContent =
+ { device: 'Now: screen lock. Changing the screen lock or adding a fingerprint never deletes the vault.',
+ code: 'Now: app code. To go back to the screen lock, type the current code above.',
+ password: 'Now: vault password. To go back to the screen lock, type it above.',
+ none: 'Now: no protection - anyone holding the phone unlocked can open the vault.' }[unlockMode]
+ + (canDeviceLock ? '' : ' This phone has no screen lock.');
+ document.getElementById('btnUsePwd').hidden =
+ !(authMode === 'open' && unlockMode === 'device' && hasContainer);
+}
+function modeField() {
+ var el = document.getElementById('sPinNew'), v = el.value;
+ el.value = '';
+ return v;
+}
+document.getElementById('sModeCode').addEventListener('click', function () {
+ var v = modeField();
+ if (!v) { toast('Type the new code above first'); return; }
send('pinset?c=' + encodeURIComponent(v));
- document.getElementById('sPinNew').value = '';
+});
+document.getElementById('sModePwd').addEventListener('click', function () {
+ var v = modeField();
+ if (!v) { toast('Type the vault password above first'); return; }
+ send('pinset?pw=1&c=' + encodeURIComponent(v));
+});
+document.getElementById('sModeDevice').addEventListener('click', function () {
+ if (unlockMode === 'device') { toast('Already using the screen lock'); return; }
+ var v = modeField();
+ if (!v && unlockMode !== 'none') { toast('Type the current code or password above first'); return; }
+ send('pinclear?c=' + encodeURIComponent(v));
+});
+document.getElementById('btnUsePwd').addEventListener('click', function () {
+ PM.setAuthMode('login');
+ document.getElementById('pass').focus();
});
document.getElementById('sWipe').addEventListener('click', function (ev) {
// DEUX APPUIS, comme pour retirer le code : un effacement sans retour ne se
@@ -1675,27 +1712,6 @@ document.getElementById('sWipe').addEventListener('click', function (ev) {
send('wipelocal');
closeSettings();
});
-document.getElementById('sPinClear').addEventListener('click', function (ev) {
- var b = ev.currentTarget;
- if (b.getAttribute('data-armed') === null) {
- b.setAttribute('data-armed', '1');
- b.textContent = 'Really remove - tap again';
- setTimeout(function () {
- b.removeAttribute('data-armed');
- b.textContent = 'Remove the unlock code';
- }, 4000);
- return;
- }
- b.removeAttribute('data-armed');
- b.textContent = 'Remove the unlock code';
- // LE CODE COURANT VOYAGE AVEC LA DEMANDE. Le coffre ouvert ne prouve rien :
- // il peut l'etre depuis une heure et rester a l'ecran. Delphi compare a ce
- // sous quoi le cache est reellement scelle, et refuse sinon.
- send('pinclear?c=' + encodeURIComponent(
- document.getElementById('sPinNew').value));
- document.getElementById('sPinNew').value = '';
-});
-
function goList() {
closeMenu();
document.body.classList.remove('on-detail');
@@ -1826,6 +1842,12 @@ var PM = {
syncPinbox();
document.getElementById('btnAuth').textContent =
(mode === 'register') ? 'Create vault' : 'Sign in';
+ syncUnlockUi();
+ },
+
+ setUnlockMode: function (mode, canDevice, container) {
+ unlockMode = mode; canDeviceLock = canDevice; hasContainer = container;
+ syncUnlockUi();
},
setPinNeeded: function (on) {
diff --git a/mainApk.pas b/mainApk.pas
index 3a2b117..d1f4112 100644
--- a/mainApk.pas
+++ b/mainApk.pas
@@ -337,6 +337,7 @@ type
/// 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);
+ procedure PushUnlockMode;
/// Va chercher l'icone du site de l'entree ouverte, ou l'efface.
procedure SetEntryIcon(AFetch: Boolean);
/// Le depot a bouge, ou ne l'a plus : LE DRAPEAU ET SON TEMOIN ENSEMBLE.
@@ -534,6 +535,7 @@ begin
WebCall('PM.setAuthMode("login")')
else
WebCall('PM.setAuthMode("register")');
+ PushUnlockMode;
LCanOpen := HasVault and not FVaultUnreadable;
if LCanOpen then
@@ -1701,7 +1703,10 @@ begin
Exit // Touch a deja eu lieu plus haut
else if LAction = 'state' then
- FWebView := Param('view')
+ begin
+ FWebView := Param('view');
+ if FWebView = 'settings' then PushUnlockMode;
+ end
else if LAction = 'open' then
OpenEntry(StrToIntDef(Param('i'), -1))
@@ -1789,7 +1794,16 @@ begin
{$ENDIF}
else if LAction = 'pinset' then
- SetUnlockCode(TNetEncoding.URL.Decode(Param('c')))
+ begin
+ // MODE MOT DE PASSE = le code EST le mot de passe du coffre. On le
+ // verifie : sinon une faute de frappe scellerait sous un "mot de passe"
+ // que l'utilisateur ne retapera jamais a l'identique.
+ if (Param('pw') = '1') and
+ ((FPlain = '') or (TNetEncoding.URL.Decode(Param('c')) <> CachePwd)) then
+ WebCall('PM.toast("Wrong vault password")')
+ else
+ SetUnlockCode(TNetEncoding.URL.Decode(Param('c')));
+ end
else if LAction = 'pinclear' then
ClearUnlockCode(TNetEncoding.URL.Decode(Param('c')))
@@ -3070,6 +3084,7 @@ begin
Log('Unlock code set');
WebCall('PM.toast("Unlock code set")');
WebCall('PM.pinChanged()');
+ PushUnlockMode;
except
on E: Exception do
begin
@@ -3079,6 +3094,28 @@ begin
end;
end;
+/// Dit a la page comment le cache est scelle. 'password' = scelle sous un code
+/// egal au mot de passe du coffre - connu seulement une fois ouvert (FPinSealed).
+procedure TForm8.PushUnlockMode;
+var
+ LMode: string;
+begin
+ if VaultNeedsPin then
+ begin
+ if (FPinSealed <> '') and (FPinSealed = CachePwd) then
+ LMode := 'password'
+ else
+ LMode := 'code';
+ end
+ else if VaultNeedsAuth then
+ LMode := 'device'
+ else
+ LMode := 'none';
+ WebCall(Format('PM.setUnlockMode("%s", %s, %s)',
+ [LMode, LowerCase(BoolToStr(BiometricAvailable, True)),
+ LowerCase(BoolToStr(HasLocalContainer, True))]));
+end;
+
function TForm8.CachePwd: string;
begin
if HasLocalContainer then Result := FVaultPwd else Result := FSyncPwd;
@@ -3117,7 +3154,10 @@ begin
Exit;
end;
try
- SaveVault(FPlain, FETag, CachePwd, BiometricAvailable, False, '',
+ // Cle NEUVE : le verrouillage d'ecran a pu changer pendant que le code
+ // protegeait, et une ancienne paire invalidee scellerait un fichier
+ // impossible a rouvrir.
+ SaveVault(FPlain, FETag, CachePwd, BiometricAvailable, True, '',
FKey, FKeySalt, FKeyIters, True);
if VaultNeedsPin then
begin
@@ -3130,6 +3170,7 @@ begin
Log('Unlock code removed');
WebCall('PM.toast("Unlock code removed")');
WebCall('PM.pinChanged()');
+ PushUnlockMode;
ShowUnlock;
except
on E: Exception do