/api/login locked every client for 30 s after five failures from anyone.
Anyone who could reach the login page could keep the owner locked out by
failing on purpose. If no login succeeded after a lockout, the lock also
returned from 2^31 to 2^32 ms (about 24.9 to 49.7 days) later, because the
deadline was never cleared and was compared as a signed difference.
Count failures per remote address instead. Five failures lock that address
for 30 s, as before. A shared budget caps failures from all addresses
together, so changing address does not add guesses: it holds six failures
and refills one every 6 s, the old global rate, so one failing address can
never empty it on its own. While it is empty every client waits, as before.
Lock times are measured as elapsed time.
The policy is a pure header, WebConfigLoginThrottle.h.
test_webconfig_login_throttle.py runs it directly (isolation, boundaries,
one-hour rate bounds, millis() half-wrap, saturation, eviction) and runs the
real handleLogin with ArduinoJson under ASan/UBSan. Putting every client on
one key, as the old code did, fails the handler test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Restart the retry interval without treating queue cleanup as completed USB transmission. Cover cancellation journals, fresh recovery deadlines, real progress and rollover, with historical policy and runtime negative controls.
Require a real raw-table save for same-value channel SETs. This repairs the false acknowledgement after successful constructor recovery of an older backup followed by a failed candidate write.
Keep resolved alias keys, raw AUTO policy and runtime generation untouched. Preserve GET and unchanged contact behavior, changed-policy validation and indeterminate-publication quarantine.
Cover real stale-backup creation, failure/retry, reboot and exact old-skip controls. Add actual alias/BaseChatMesh and raw app-key regression tests on all four backends. Verified 117 related host tests, 16 final caller rechecks, four firmware qualifications and linked nRF52 crypto checks.
Latch only channel storage on Indeterminate writer outcomes, including failed transaction setup. Preserve ordinary failure retries, confirmed rollback, contacts and the live accepted channel keys.
Exercise actual CLI and binary callers with all four storage backends, reboot behavior and exact missing-latch negative controls. Share TX storage failure diagnostics to retain the strict Wio-E5 Mini flash gate.
Verified 103 related host tests, four platform firmware qualifications and linked nRF52 crypto/stack checks. A separate stale-backup constructor/no-op acknowledgement case remains under audit.
Extract the production contact flush, retry and UI shutdown helpers instead of leaving stale fixture-only methods. Keep rollover negative controls and cover volatile contacts, accepted dirty work, authoritative repair and rebuild failures.
Recheck cached immutable paths before resetting the live table after raw I/O failure. Keep accepted RAM mutations, current jobs and save deadlines when reads recover; stronger source or publication uncertainty still forces full recovery. Use the existing recovery byte and a fixed scratch buffer, with no cache allocation or eviction.
Cover full-cache transient recovery, persistent I/O and checksum failures, nRF unread-scope restoration, active ESP jobs, real uncertain publication and unchanged lazy deadlines with sanitizer tests and restored-reset negative controls.
Do not classify legacy or page-name stat errors as unread payloads. Keep candidate contact files unchanged, retry source selection, and use bounded volatile operation if authority remains unknown. Cover legacy absence, downgrade leftovers, cleanup-time metadata recovery and persistent faults with actual-source sanitizer tests and restored-bug negative controls.
Verify fallback namespace moves before accepting publication or rollback. Reload readable contact images at a safe host boundary, discard only unreadable contact data after bounded retries, and permit volatile operation when storage cannot recover. Preserve unrelated stores and fail explicit durability requests truthfully.
Keep existing flash, RAM, OTA and capability limits by streaming nRF52 preferences through the validated wire table and sharing identical contact deadline resets. Add fault-injection, sanitizer, legacy-image parity and CLI lifecycle regressions.
Verify public images after every rename attempt, expose publication outcomes, and use an independent CRC32C fingerprint so valid IEEE-CRC-tailed images cannot mask a stale target. Preserve persistent formats and reject directories for empty images.
Reconcile uncertain migration journals before choosing filesystem authority. Preserve retained contact snapshots when page publication is unconfirmed without clearing dirty state or acknowledging the new page generation.
Add readback, rename, CRC-tail, migration reboot/quarantine, and snapshot eviction regressions. Keep complete RAK Full Companion within the unchanged OTA ceiling through equivalent code compaction, with no feature or validation cuts.