feat(android): a settings screen, and the unlock code can finally be removed
Three things of different natures lived in collapsible panels on the home screen - repository credentials, the unlock code, the log - on the one screen where one mostly wants to open one's vault. They move to a settings sheet, reachable from the list too. A sheet, not a fourth view of the rail: each view costs its transform rules and a place in back-key navigation, and settings is not somewhere one moves about - it is a parenthesis one opens and closes. The unlock code can now be REMOVED. It could not before: clearing the field meant "nothing typed", not "drop the protection", so one could set a code and never get out. It requires an open vault, and that is the proof being asked for - the cache only let itself be read under the right code. Without that, anyone holding the unlocked phone could lift the protection without knowing it. The refusal that guards every other path stays: it is what stopped a sync from silently undoing a code. Removing is the one deliberate way out, and it says so at the call site. The old fields stay in the document as the source Delphi knows; the sheet is only a view of them. Emptying them would lose the configuration at the first sync.
This commit is contained in:
@@ -98,7 +98,8 @@ function HasVault: Boolean;
|
|||||||
procedure SaveVault(const APlainJson, AETag, ASyncPwd: string;
|
procedure SaveVault(const APlainJson, AETag, ASyncPwd: string;
|
||||||
ARequireAuth: Boolean = False; AFreshKey: Boolean = False;
|
ARequireAuth: Boolean = False; AFreshKey: Boolean = False;
|
||||||
const APin: string = ''; const AKey: TBytes = nil;
|
const APin: string = ''; const AKey: TBytes = nil;
|
||||||
const ASalt: TBytes = nil; AIterations: Integer = 0);
|
const ASalt: TBytes = nil; AIterations: Integer = 0;
|
||||||
|
AClearPin: Boolean = False);
|
||||||
|
|
||||||
/// Le fichier local est-il scelle sous un code d'application ? Lu dans
|
/// Le fichier local est-il scelle sous un code d'application ? Lu dans
|
||||||
/// l'en-tete, sans rien dechiffrer.
|
/// l'en-tete, sans rien dechiffrer.
|
||||||
@@ -887,7 +888,7 @@ end;
|
|||||||
|
|
||||||
procedure SaveVault(const APlainJson, AETag, ASyncPwd: string;
|
procedure SaveVault(const APlainJson, AETag, ASyncPwd: string;
|
||||||
ARequireAuth, AFreshKey: Boolean; const APin: string;
|
ARequireAuth, AFreshKey: Boolean; const APin: string;
|
||||||
const AKey, ASalt: TBytes; AIterations: Integer);
|
const AKey, ASalt: TBytes; AIterations: Integer; AClearPin: Boolean);
|
||||||
{$IF DEFINED(ANDROID)}
|
{$IF DEFINED(ANDROID)}
|
||||||
var
|
var
|
||||||
LWrap: TJSONObject;
|
LWrap: TJSONObject;
|
||||||
@@ -908,7 +909,12 @@ begin
|
|||||||
//
|
//
|
||||||
// Retirer le code demanderait donc un geste explicite, qui n'existe pas
|
// Retirer le code demanderait donc un geste explicite, qui n'existe pas
|
||||||
// encore : aujourd'hui on le remplace en le retapant.
|
// encore : aujourd'hui on le remplace en le retapant.
|
||||||
if (APin = '') and VaultNeedsPin then
|
// AClearPin EST LA SEULE SORTIE, et elle se demande. Le refus ci-dessous
|
||||||
|
// protege tous les autres chemins - c'est lui qui a empeche une
|
||||||
|
// synchronisation de defaire un code en silence. Retirer un code reste
|
||||||
|
// possible, mais seulement quand quelqu'un l'a decide et vient de prouver
|
||||||
|
// qu'il le connaissait en ouvrant le coffre.
|
||||||
|
if (APin = '') and VaultNeedsPin and not AClearPin then
|
||||||
begin
|
begin
|
||||||
FLastStoreError := 'cache sealed under an unlock code; refusing to ' +
|
FLastStoreError := 'cache sealed under an unlock code; refusing to ' +
|
||||||
'rewrite it without one';
|
'rewrite it without one';
|
||||||
|
|||||||
+23
-3
@@ -120,12 +120,32 @@ prouve rien.
|
|||||||
côte à côte**. Ils demandent deux gestes différents ; les confondre dirait
|
côte à côte**. Ils demandent deux gestes différents ; les confondre dirait
|
||||||
« quelque chose ne va pas » sans dire quoi.
|
« quelque chose ne va pas » sans dire quoi.
|
||||||
|
|
||||||
### F. Pièces jointes
|
### F. Réglages
|
||||||
|
|
||||||
|
1. Roue dentée dans la liste, ou *Settings* sur l'accueil → l'écran s'ouvre.
|
||||||
|
2. Les trois champs du dépôt doivent porter **les valeurs en place**, pas du
|
||||||
|
vide : ils ne sont qu'une vue des champs que Delphi connaît déjà.
|
||||||
|
3. Modifier l'URL, revenir par la flèche, *Sync* → la nouvelle valeur sert.
|
||||||
|
C'est la contre-épreuve du report à la fermeture : un réglage modifié puis
|
||||||
|
refermé **sans quitter le champ** doit compter.
|
||||||
|
4. Touche **retour** dans les réglages → elle referme **sans** verrouiller ni
|
||||||
|
revenir à la liste.
|
||||||
|
5. **Poser un code** depuis les réglages : taper, *Set this code*, puis ouvrir
|
||||||
|
le coffre → *« Unlock code changed »*. Le sceau se pose toujours à
|
||||||
|
l'ouverture, et nulle part ailleurs.
|
||||||
|
6. **Retirer le code** : *Remove the unlock code*, deux appuis → *« Unlock code
|
||||||
|
removed »*. Fermer l'application, rouvrir → **le code n'est plus demandé**.
|
||||||
|
7. Contre-épreuve du retrait : verrouiller, puis essayer de retirer le code
|
||||||
|
sans avoir ouvert le coffre → refus *« Open the vault first »*. C'est ce qui
|
||||||
|
empêche quelqu'un tenant le téléphone déverrouillé de lever la protection
|
||||||
|
sans la connaître.
|
||||||
|
|
||||||
|
### G. Pièces jointes
|
||||||
|
|
||||||
1. Ligne *Attachment* → flèche de téléchargement → le fichier apparaît dans
|
1. Ligne *Attachment* → flèche de téléchargement → le fichier apparaît dans
|
||||||
*Téléchargements* sous son nom, accents et arabe compris.
|
*Téléchargements* sous son nom, accents et arabe compris.
|
||||||
|
|
||||||
### G. Code de déverrouillage
|
### H. Code de déverrouillage
|
||||||
|
|
||||||
1. Poser un code, ouvrir le coffre, fermer, rouvrir → il est demandé.
|
1. Poser un code, ouvrir le coffre, fermer, rouvrir → il est demandé.
|
||||||
2. Code faux → *« Wrong unlock code »*, et **Open vault reste offert** (le
|
2. Code faux → *« Wrong unlock code »*, et **Open vault reste offert** (le
|
||||||
@@ -135,7 +155,7 @@ prouve rien.
|
|||||||
4. Contre-épreuve : taper n'importe quoi dans le champ du code puis *Sync* →
|
4. Contre-épreuve : taper n'importe quoi dans le champ du code puis *Sync* →
|
||||||
le code **ne doit pas changer**.
|
le code **ne doit pas changer**.
|
||||||
|
|
||||||
### H. Empaquetage
|
### I. Empaquetage
|
||||||
|
|
||||||
1. `build-apk.ps1 -Release -Keystore ... -Alias ...` → la sortie doit afficher
|
1. `build-apk.ps1 -Release -Keystore ... -Alias ...` → la sortie doit afficher
|
||||||
`Signer #1 certificate DN: CN=R Zakarya`. Si elle affiche `CN=Android
|
`Signer #1 certificate DN: CN=R Zakarya`. Si elle affiche `CN=Android
|
||||||
|
|||||||
+148
-7
@@ -305,6 +305,20 @@
|
|||||||
font: 11px/1.45 monospace; white-space: pre-wrap; word-break: break-all;
|
font: 11px/1.45 monospace; white-space: pre-wrap; word-break: break-all;
|
||||||
-webkit-user-select: text; user-select: text;
|
-webkit-user-select: text; user-select: text;
|
||||||
}
|
}
|
||||||
|
/* LES REGLAGES SONT UN VOILE, PAS UNE QUATRIEME VUE DU RAIL. Chaque vue du
|
||||||
|
rail coute ses regles de transformation et une place dans la navigation
|
||||||
|
par la touche retour ; les reglages ne sont pas un lieu ou l'on circule,
|
||||||
|
c'est une parenthese qu'on ouvre et qu'on referme. */
|
||||||
|
.sheet { position: fixed; inset: 0; z-index: 80; display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
background: linear-gradient(var(--bg-top), var(--bg-bot)); }
|
||||||
|
body.on-settings .sheet { display: flex; }
|
||||||
|
.sheet h2 { margin: 18px 4px 6px; font-size: 13px; font-weight: 600;
|
||||||
|
color: var(--muted); text-transform: uppercase;
|
||||||
|
letter-spacing: .06em; }
|
||||||
|
.sheet .note { color: var(--muted); font-size: 13px; margin: 6px 4px 0;
|
||||||
|
line-height: 1.45; }
|
||||||
|
|
||||||
[hidden] { display: none !important; }
|
[hidden] { display: none !important; }
|
||||||
|
|
||||||
.toast {
|
.toast {
|
||||||
@@ -363,8 +377,9 @@
|
|||||||
<button class="btn wide main" id="btnOpen">➜ Open vault</button>
|
<button class="btn wide main" id="btnOpen">➜ Open vault</button>
|
||||||
<button class="btn wide" id="btnSync">↻ Sync</button>
|
<button class="btn wide" id="btnSync">↻ Sync</button>
|
||||||
<div class="pair">
|
<div class="pair">
|
||||||
<button class="btn" id="btnCfg" data-panel="cfg">⚙ Server
|
<!-- Plus de chevron : ce bouton n'ouvre plus un panneau sous lui,
|
||||||
settings<span class="chev">▾</span></button>
|
il ouvre un ecran. Le garder promettrait un depliage. -->
|
||||||
|
<button class="btn" id="btnCfg">⚙ Settings</button>
|
||||||
<button class="btn" id="btnLog" data-panel="log">≡
|
<button class="btn" id="btnLog" data-panel="log">≡
|
||||||
Log<span class="chev">▾</span></button>
|
Log<span class="chev">▾</span></button>
|
||||||
</div>
|
</div>
|
||||||
@@ -446,6 +461,13 @@
|
|||||||
autocapitalize="none" spellcheck="false">
|
autocapitalize="none" spellcheck="false">
|
||||||
<div class="clear" id="qx">×</div>
|
<div class="clear" id="qx">×</div>
|
||||||
</div>
|
</div>
|
||||||
|
<button class="ico" id="gear" aria-label="Settings">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||||
|
stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<circle cx="12" cy="12" r="3.2" />
|
||||||
|
<path d="M12 3.5v2M12 18.5v2M3.5 12h2M18.5 12h2M6 6l1.4 1.4M16.6 16.6L18 18M18 6l-1.4 1.4M7.4 16.6L6 18" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
<button class="ico" id="new" aria-label="New entry">
|
<button class="ico" id="new" aria-label="New entry">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||||
stroke-width="2" stroke-linecap="round">
|
stroke-width="2" stroke-linecap="round">
|
||||||
@@ -481,6 +503,53 @@
|
|||||||
<div class="menu" id="menu" hidden></div>
|
<div class="menu" id="menu" hidden></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- REGLAGES. Ils rassemblent ce qui vivait en deux panneaux repliables sur
|
||||||
|
l'ecran d'accueil : les coordonnees du depot d'un cote, le code de
|
||||||
|
deverrouillage de l'autre, et le journal en troisieme. Trois choses de
|
||||||
|
nature differente sur l'ecran ou l'on veut surtout ouvrir son coffre. -->
|
||||||
|
<div class="sheet" id="settings">
|
||||||
|
<div class="head">
|
||||||
|
<button class="btn" id="setBack">←</button>
|
||||||
|
<h1>Settings</h1>
|
||||||
|
</div>
|
||||||
|
<div class="scroll">
|
||||||
|
<h2>Repository</h2>
|
||||||
|
<div class="in-wrap">
|
||||||
|
<input class="field-in" id="sUrl" placeholder="endpoint URL"
|
||||||
|
autocomplete="off" autocorrect="off" autocapitalize="none"
|
||||||
|
spellcheck="false" inputmode="url">
|
||||||
|
<div class="in-x" data-clear="sUrl">×</div>
|
||||||
|
</div>
|
||||||
|
<div class="in-wrap">
|
||||||
|
<input class="field-in" id="sTok" placeholder="access token"
|
||||||
|
type="password" autocomplete="off">
|
||||||
|
<div class="in-x" data-clear="sTok">×</div>
|
||||||
|
</div>
|
||||||
|
<div class="in-wrap">
|
||||||
|
<input class="field-in" id="sPwd" placeholder="master 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>
|
||||||
|
|
||||||
|
<h2>Unlock code</h2>
|
||||||
|
<div class="in-wrap">
|
||||||
|
<input class="field-in" id="sPinNew" placeholder="new unlock code"
|
||||||
|
type="password" inputmode="numeric" autocomplete="off">
|
||||||
|
<div class="in-x" data-clear="sPinNew">×</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn wide" id="sPinSet">Set this code</button>
|
||||||
|
<button class="btn wide danger" id="sPinClear">Remove the unlock code</button>
|
||||||
|
<div class="note">The code seals the copy kept on this device. Removing it
|
||||||
|
leaves the vault readable by anyone holding the phone unlocked.</div>
|
||||||
|
|
||||||
|
<h2>Diagnostics</h2>
|
||||||
|
<button class="btn wide" id="sLog">Show the log</button>
|
||||||
|
<div class="note" id="sVersion"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="busy" id="busy"><div></div></div>
|
<div class="busy" id="busy"><div></div></div>
|
||||||
<div class="toast" id="toast"></div>
|
<div class="toast" id="toast"></div>
|
||||||
|
|
||||||
@@ -570,6 +639,14 @@ document.getElementById('btnSync').addEventListener('click', function () {
|
|||||||
// cible. Pose sur l'ECRAN, pas sur le groupe des reglages - le code a son
|
// cible. Pose sur l'ECRAN, pas sur le groupe des reglages - le code a son
|
||||||
// propre bloc depuis qu'il n'appartient plus au serveur, et sa croix serait
|
// propre bloc depuis qu'il n'appartient plus au serveur, et sa croix serait
|
||||||
// restee sans effet.
|
// restee sans effet.
|
||||||
|
document.getElementById('settings').addEventListener('click', function (ev) {
|
||||||
|
var id = ev.target.getAttribute('data-clear');
|
||||||
|
if (!id) return;
|
||||||
|
var el = document.getElementById(id);
|
||||||
|
el.value = '';
|
||||||
|
el.focus();
|
||||||
|
});
|
||||||
|
|
||||||
document.getElementById('unlock').addEventListener('click', function (ev) {
|
document.getElementById('unlock').addEventListener('click', function (ev) {
|
||||||
var id = ev.target.getAttribute('data-clear');
|
var id = ev.target.getAttribute('data-clear');
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
@@ -591,9 +668,7 @@ function togglePanel(name) {
|
|||||||
document.querySelector('[data-panel="' + n + '"]').classList.toggle('open', open);
|
document.querySelector('[data-panel="' + n + '"]').classList.toggle('open', open);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
document.getElementById('btnCfg').addEventListener('click', function () {
|
document.getElementById('btnCfg').addEventListener('click', openSettings);
|
||||||
togglePanel('cfg');
|
|
||||||
});
|
|
||||||
document.getElementById('btnLog').addEventListener('click', function () {
|
document.getElementById('btnLog').addEventListener('click', function () {
|
||||||
togglePanel('log');
|
togglePanel('log');
|
||||||
});
|
});
|
||||||
@@ -1162,6 +1237,7 @@ document.getElementById('fields').addEventListener('click', function (ev) {
|
|||||||
+ '&k=' + newKind);
|
+ '&k=' + newKind);
|
||||||
});
|
});
|
||||||
document.getElementById('new').addEventListener('click', openNewEntry);
|
document.getElementById('new').addEventListener('click', openNewEntry);
|
||||||
|
document.getElementById('gear').addEventListener('click', openSettings);
|
||||||
|
|
||||||
// LE MENU DE L'ENTREE, et la suppression qui y vit.
|
// LE MENU DE L'ENTREE, et la suppression qui y vit.
|
||||||
//
|
//
|
||||||
@@ -1322,6 +1398,60 @@ document.addEventListener('click', function (ev) {
|
|||||||
closeMenu();
|
closeMenu();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// LES REGLAGES. Ils lisent et ecrivent les MEMES champs que l'accueil - la
|
||||||
|
// page n'en garde qu'une copie, Delphi reste la seule source.
|
||||||
|
function openSettings() {
|
||||||
|
document.getElementById('sUrl').value = elUrl.value;
|
||||||
|
document.getElementById('sTok').value = elTok.value;
|
||||||
|
document.getElementById('sPwd').value = elPwd.value;
|
||||||
|
document.getElementById('sPinNew').value = '';
|
||||||
|
document.body.classList.add('on-settings');
|
||||||
|
send('state?view=settings');
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeSettings() {
|
||||||
|
// Ce qui a ete tape ici redescend vers Delphi avant de fermer, sinon un
|
||||||
|
// reglage modifie puis referme sans quitter le champ serait perdu.
|
||||||
|
elUrl.value = document.getElementById('sUrl').value.trim();
|
||||||
|
elTok.value = document.getElementById('sTok').value.trim();
|
||||||
|
elPwd.value = document.getElementById('sPwd').value;
|
||||||
|
pushConfig();
|
||||||
|
document.body.classList.remove('on-settings');
|
||||||
|
send('state?view=' + view);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('setBack').addEventListener('click', closeSettings);
|
||||||
|
document.getElementById('sLog').addEventListener('click', function () {
|
||||||
|
closeSettings();
|
||||||
|
if (document.getElementById('log').hidden) togglePanel('log');
|
||||||
|
});
|
||||||
|
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');
|
||||||
|
});
|
||||||
|
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';
|
||||||
|
send('pinclear');
|
||||||
|
closeSettings();
|
||||||
|
});
|
||||||
|
|
||||||
function goList() {
|
function goList() {
|
||||||
closeMenu();
|
closeMenu();
|
||||||
document.body.classList.remove('on-detail');
|
document.body.classList.remove('on-detail');
|
||||||
@@ -1391,11 +1521,17 @@ var PM = {
|
|||||||
o.style.opacity = busy ? .4 : 1;
|
o.style.opacity = busy ? .4 : 1;
|
||||||
s.style.opacity = busy ? .4 : 1;
|
s.style.opacity = busy ? .4 : 1;
|
||||||
},
|
},
|
||||||
|
/// LES CHAMPS RESTENT LA SOURCE, l'ecran de reglages n'en est qu'une vue.
|
||||||
|
/// Ils ne s'affichent plus - le panneau repliable a cede la place au voile -
|
||||||
|
/// mais c'est toujours d'eux que part pushConfig, et Delphi ne connait qu'eux.
|
||||||
|
/// Les vider ferait perdre la configuration a la premiere synchronisation.
|
||||||
setConfig: function (url, tok, pwd, show) {
|
setConfig: function (url, tok, pwd, show) {
|
||||||
// elPin volontairement absent : rien ne le restaure, jamais.
|
// elPin volontairement absent : rien ne le restaure, jamais.
|
||||||
elUrl.value = url; elTok.value = tok; elPwd.value = pwd;
|
elUrl.value = url; elTok.value = tok; elPwd.value = pwd;
|
||||||
// Replier des champs vides revient a cacher la seule chose a faire.
|
// Rien a deplier : c'est le voile des reglages qui les montre desormais.
|
||||||
if (show !== !document.getElementById('cfg').hidden) togglePanel('cfg');
|
// Un depot pas encore configure s'annonce donc autrement - le bouton
|
||||||
|
// d'accueil dit "Download vault" et l'ecran, "No vault on this device".
|
||||||
|
if (show) toast('Set the repository in Settings');
|
||||||
},
|
},
|
||||||
|
|
||||||
/// LE JOURNAL SORT DE LA VUE EN RELEASE, sans disparaitre.
|
/// LE JOURNAL SORT DE LA VUE EN RELEASE, sans disparaitre.
|
||||||
@@ -1492,6 +1628,9 @@ var PM = {
|
|||||||
document.getElementById('lock').classList.toggle('ahead', !!on);
|
document.getElementById('lock').classList.toggle('ahead', !!on);
|
||||||
document.getElementById('btnSync').classList.toggle('ahead', !!on);
|
document.getElementById('btnSync').classList.toggle('ahead', !!on);
|
||||||
},
|
},
|
||||||
|
setVersion: function (v) {
|
||||||
|
document.getElementById('sVersion').textContent = v;
|
||||||
|
},
|
||||||
setBusy: function (on) {
|
setBusy: function (on) {
|
||||||
if (on) document.getElementById('busy').firstChild.innerHTML =
|
if (on) document.getElementById('busy').firstChild.innerHTML =
|
||||||
ico('loader', 'Working') + '<span>Please wait...</span>';
|
ico('loader', 'Working') + '<span>Please wait...</span>';
|
||||||
@@ -1502,6 +1641,8 @@ var PM = {
|
|||||||
/// Sans cela, un geste d'annulation fermait le coffre - le contraire de ce
|
/// Sans cela, un geste d'annulation fermait le coffre - le contraire de ce
|
||||||
/// qu'il veut dire.
|
/// qu'il veut dire.
|
||||||
clearSelection: function () { clearSel(); },
|
clearSelection: function () { clearSel(); },
|
||||||
|
/// La touche retour referme les reglages avant de toucher au coffre.
|
||||||
|
closeSettings: function () { closeSettings(); },
|
||||||
// Efface tout ce qui est en clair. Appele au passage en arriere-plan et au
|
// Efface tout ce qui est en clair. Appele au passage en arriere-plan et au
|
||||||
// verrouillage : le tas JS n'est pas efface par le masquage de la vue.
|
// verrouillage : le tas JS n'est pas efface par le masquage de la vue.
|
||||||
wipe: function () {
|
wipe: function () {
|
||||||
|
|||||||
+65
@@ -303,6 +303,9 @@ type
|
|||||||
procedure PublishPending;
|
procedure PublishPending;
|
||||||
/// Demande au depot s'il a bouge, sans rien adopter.
|
/// Demande au depot s'il a bouge, sans rien adopter.
|
||||||
procedure ProbeRemote;
|
procedure ProbeRemote;
|
||||||
|
/// Retire le code de deverrouillage : le cache se rescelle sous la seule
|
||||||
|
/// cle de l'appareil. Exige un coffre ouvert.
|
||||||
|
procedure ClearUnlockCode;
|
||||||
procedure ReopenEntryByUuid(const AUuid: string);
|
procedure ReopenEntryByUuid(const AUuid: string);
|
||||||
procedure OnClipTimer(Sender: TObject);
|
procedure OnClipTimer(Sender: TObject);
|
||||||
procedure OnDeadline(Sender: TObject);
|
procedure OnDeadline(Sender: TObject);
|
||||||
@@ -406,6 +409,7 @@ begin
|
|||||||
// cache par la version du depot, et ce qui attend ici serait perdu.
|
// cache par la version du depot, et ce qui attend ici serait perdu.
|
||||||
FPending := HasPendingFlag;
|
FPending := HasPendingFlag;
|
||||||
PushConfig;
|
PushConfig;
|
||||||
|
WebCall('PM.setVersion("Coffre 1.0.0")');
|
||||||
ShowUnlock;
|
ShowUnlock;
|
||||||
{$IFNDEF DEBUG}
|
{$IFNDEF DEBUG}
|
||||||
// Le journal quitte l'ecran d'accueil, sans quitter l'application : un appui
|
// Le journal quitte l'ecran d'accueil, sans quitter l'application : un appui
|
||||||
@@ -530,6 +534,16 @@ begin
|
|||||||
end;
|
end;
|
||||||
// C'est la PAGE qui sait ce qu'elle affiche - Delphi ne le devine pas. Elle
|
// C'est la PAGE qui sait ce qu'elle affiche - Delphi ne le devine pas. Elle
|
||||||
// le declare a chaque changement de vue (cmd://state).
|
// le declare a chaque changement de vue (cmd://state).
|
||||||
|
// LES REGLAGES SE REFERMENT D'ABORD. Ils sont une parenthese posee par-dessus
|
||||||
|
// le reste : la touche retour la ferme, elle ne saute pas ce qu'il y a
|
||||||
|
// derriere.
|
||||||
|
if FWebView = 'settings' then
|
||||||
|
begin
|
||||||
|
WebCall('PM.closeSettings()');
|
||||||
|
Key := 0;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
// UNE SELECTION EN COURS S'ANNULE D'ABORD. Verrouiller le coffre parce qu'on
|
// UNE SELECTION EN COURS S'ANNULE D'ABORD. Verrouiller le coffre parce qu'on
|
||||||
// a voulu annuler un choix serait le contraire de ce que le geste veut dire.
|
// a voulu annuler un choix serait le contraire de ce que le geste veut dire.
|
||||||
if FWebView = 'select' then
|
if FWebView = 'select' then
|
||||||
@@ -1605,6 +1619,9 @@ begin
|
|||||||
TNetEncoding.URL.Decode(Param('k')),
|
TNetEncoding.URL.Decode(Param('k')),
|
||||||
TNetEncoding.URL.Decode(Param('d')))
|
TNetEncoding.URL.Decode(Param('d')))
|
||||||
|
|
||||||
|
else if LAction = 'pinclear' then
|
||||||
|
ClearUnlockCode
|
||||||
|
|
||||||
else if LAction = 'delentry' then
|
else if LAction = 'delentry' then
|
||||||
DeleteEntriesAt(TNetEncoding.URL.Decode(Param('i')))
|
DeleteEntriesAt(TNetEncoding.URL.Decode(Param('i')))
|
||||||
|
|
||||||
@@ -2518,6 +2535,54 @@ end;
|
|||||||
/// pas repondre sans lui - mais il est jete sans etre dechiffre : pas de
|
/// pas repondre sans lui - mais il est jete sans etre dechiffre : pas de
|
||||||
/// derivation, pas d'ecriture, seulement une comparaison de chaines. Le prix
|
/// derivation, pas d'ecriture, seulement une comparaison de chaines. Le prix
|
||||||
/// est en reseau, pas en temps ni en batterie.
|
/// est en reseau, pas en temps ni en batterie.
|
||||||
|
/// RETIRER LE CODE DE DEVERROUILLAGE.
|
||||||
|
///
|
||||||
|
/// Il manquait : vider le champ voulait dire "rien tape", pas "enlever la
|
||||||
|
/// protection", et rien d'autre ne le proposait. On pouvait donc en poser un
|
||||||
|
/// et jamais en sortir.
|
||||||
|
///
|
||||||
|
/// EXIGE UN COFFRE OUVERT, et c'est la preuve qu'on cherche : le cache ne
|
||||||
|
/// s'est laisse lire que sous le bon code. Sans cette condition, n'importe qui
|
||||||
|
/// tenant l'appareil deverrouille pourrait retirer la protection sans la
|
||||||
|
/// connaitre.
|
||||||
|
procedure TForm8.ClearUnlockCode;
|
||||||
|
begin
|
||||||
|
if FBusy then Exit;
|
||||||
|
if not VaultNeedsPin then
|
||||||
|
begin
|
||||||
|
WebCall('PM.toast("No unlock code to remove")');
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
if (FPlain = '') or (FSyncPwd = '') then
|
||||||
|
begin
|
||||||
|
WebCall('PM.toast("Open the vault first")');
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
try
|
||||||
|
SaveVault(FPlain, FETag, FSyncPwd, BiometricAvailable, False, '',
|
||||||
|
FKey, FKeySalt, FKeyIters, True);
|
||||||
|
if VaultNeedsPin then
|
||||||
|
begin
|
||||||
|
Log('Unlock code not removed: ' + LastStoreError);
|
||||||
|
WebCall('PM.toast("Could not remove the unlock code")');
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
FPinSealed := '';
|
||||||
|
FPin := '';
|
||||||
|
FPinNew := '';
|
||||||
|
Log('Unlock code removed');
|
||||||
|
WebCall('PM.toast("Unlock code removed")');
|
||||||
|
WebCall('PM.pinChanged()');
|
||||||
|
ShowUnlock;
|
||||||
|
except
|
||||||
|
on E: Exception do
|
||||||
|
begin
|
||||||
|
Log('Unlock code not removed: ' + E.ClassName + ' - ' + E.Message);
|
||||||
|
WebCall('PM.toast("Could not remove the unlock code")');
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TForm8.ProbeRemote;
|
procedure TForm8.ProbeRemote;
|
||||||
begin
|
begin
|
||||||
if FBusy or (FUrl = '') or (FToken = '') then Exit;
|
if FBusy or (FUrl = '') or (FToken = '') then Exit;
|
||||||
|
|||||||
Reference in New Issue
Block a user