summaryrefslogtreecommitdiff
path: root/source/ui/PinView.mc
diff options
context:
space:
mode:
authorcirakg <cirakg@cirakg.xyz>2026-10-27 01:01:18 +0100
committercirakg <cirakg@cirakg.xyz>2026-10-27 01:01:18 +0100
commitbc4cc19df5f53519ca1aabd3cf161b6d78ffc16c (patch)
tree3242a63f603882d723bd0d718d043c30a9f11784 /source/ui/PinView.mc
parent34daecaa25e5bdd995179a2b4b9d922f8bbb3b54 (diff)
fix(pin): the work after a PIN and the change queue run in steps
After a correct or new PIN, promoting pending entries and applying waiting "Require PIN" changes ran in the event of the last PBKDF2 step; 16 waiting changes tripped the watchdog on the Forerunner 70. ChangeQueue.LockJob now does it in steps while the PIN screen shows "Checking...", saves what it did to the results and refreshes the glance after Set PIN too. The list title decrypted every waiting change at each start. Queue items are now [action, box] (aad OTPW-Q-2 + action code), so they are counted without decrypting; 0.9.0 items are still read. A replacement is checked when it arrives and its material is sealed apart (qm.<n>). Large buffers are wiped and UTF-8-checked in pieces (Jobs.Wiper, Bytes.utf8Prefix, SealedBox.openKeep/sealKeep). "Phone changes" reads behind "Reading...", and Confirm all / Reject all act only on the changes shown. Storage full no longer stops the app at the PIN. Found by the review of b8addc8/096b5a4 and a new make watchdog test; the diff was reviewed again and its findings fixed. fr70: make lint, make test (176), make watchdog (19 cases at two steps per event), make screenshots pass; list_locked and list_reset goldens show "Results ready (menu)". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'source/ui/PinView.mc')
-rw-r--r--source/ui/PinView.mc62
1 files changed, 45 insertions, 17 deletions
diff --git a/source/ui/PinView.mc b/source/ui/PinView.mc
index af18e2b..da032ad 100644
--- a/source/ui/PinView.mc
+++ b/source/ui/PinView.mc
@@ -16,7 +16,9 @@
// * Entered digits show as dots. A wrong PIN vibrates and shows any wait.
// * Creating or changing the PIN asks twice.
// * Key derivation (about 1 s) runs as a job on a timer, so the screen
-// shows "Checking..." and the watchdog never trips.
+// shows "Checking..." and the watchdog never trips. So does the work
+// after a correct or new PIN (LockJob: pending entries are promoted,
+// waiting "Require PIN" changes applied); its lines go to the results.
// The typed digits are a ByteArray that is wiped after every attempt.
import Toybox.Attention;
@@ -58,6 +60,10 @@ class PinView extends WatchUi.View {
private var _jobPin as ByteArray? = null;
// The running derivation's timer driver (kept so it isn't collected).
var runner as Jobs.JobRunner? = null;
+ private var _lockJob as LockJob? = null;
+ // A LockJob ran for this screen's PIN (a legacy PIN's new PIN runs a
+ // second one, which adds to the first one's lines).
+ private var _lockJobRan as Boolean = false;
private var _ticker as Timer.Timer? = null;
private var _keys as Array<Array<Number>> = [] as Array<Array<Number>>; // [x, y, w, h, key]
private var _shownLogged as Boolean = false;
@@ -79,6 +85,11 @@ class PinView extends WatchUi.View {
}
function onHide() as Void {
+ if (_lockJobRan && _lockJob == null) {
+ // Closed (or replaced): a "Confirm all" that follows has taken
+ // the lock lines already; else they are in the results.
+ ChangeQueue.takeLockLines();
+ }
var ticker = _ticker;
if (ticker != null) {
ticker.stop();
@@ -234,24 +245,16 @@ class PinView extends WatchUi.View {
}
function onUnlockDone() as Void {
- busy = false;
- _shownLogged = false;
Bytes.wipe(_jobPin);
_jobPin = null;
var vault = AppState.theVault();
if (vault.finishUnlock(_job as PinJob)) {
_job = null;
- vault.promotePending();
- ChangeQueue.applyLocks(vault);
- // Unlocked: "Encrypt names" can now reach locked entries.
- AppState.processSettings();
- if (legacy) {
- askForNewPin();
- return;
- }
- succeed();
+ startLockJob();
return;
}
+ busy = false;
+ _shownLogged = false;
_job = null;
buzz();
if (!vault.hasPin()) {
@@ -264,14 +267,39 @@ class PinView extends WatchUi.View {
}
function onSetDone() as Void {
- busy = false;
Bytes.wipe(_jobPin);
_jobPin = null;
- var vault = AppState.theVault();
- vault.finishSetPin(_job as PinJob);
+ AppState.theVault().finishSetPin(_job as PinJob);
_job = null;
- vault.promotePending();
- ChangeQueue.applyLocks(vault);
+ startLockJob();
+ }
+
+ // Unlocked: promote the pending entries and apply waiting "Require
+ // PIN" changes in steps, still showing the busy state (BACK waits).
+ private function startLockJob() as Void {
+ var job = new LockJob(AppState.theVault(), !_lockJobRan);
+ _lockJobRan = true;
+ _lockJob = job;
+ var r = new Jobs.JobRunner(job, 1, method(:onLockJobDone));
+ r.start();
+ runner = r;
+ }
+
+ function onLockJobDone() as Void {
+ busy = false;
+ _shownLogged = false;
+ var job = _lockJob as LockJob;
+ _lockJob = null;
+ if (job.lines.size() > 0) {
+ Results.add(job.lines); // the list says "Results ready (menu)"
+ }
+ // "Encrypt names" can now reach locked entries, and a lock just
+ // applied changes what the glance may show.
+ AppState.processSettings();
+ if (legacy) {
+ askForNewPin();
+ return;
+ }
succeed();
}