fix(lite): address adversarial audit findings in session's lite work

Re-audited this session's lite-wallet changes (originally written at medium
effort) and fixed the genuine issues found:

- walletReady (open path): litelib_initialize_existing returns the bare string
  "OK", which is NOT valid JSON, so the previous `json::accept(value)` check
  marked a *successful* open as not-ready. Key off a non-empty success response
  instead (the bridge already maps "Error:"/null to failure). Drops the now
  unused nlohmann include.
- sync progress: while the detached sync thread is still running, syncDone_ is
  authoritative — don't surface the backend's transient idle syncstatus
  ({"syncing":"false"} -> parser progress=1.0/complete=true) as a misleading
  100%/done. Force complete=false and zero the bogus 1.0 in the progress model.
- per-address balance: also exclude `pending` outputs (notes/utxos from an
  unconfirmed received tx) so per-address figures match confirmed/available.
- secret wiping: the settings page left the page-local request copies
  (input.request.*Request.{passphrase,seedPhrase}) unwiped, and the
  validation-only fallback path wiped nothing. Replace the single-path memzero
  with an RAII scrubber that wipes both the UI char buffers and the request
  string copies on every return path.
- concurrency: document that concurrent bridge->execute() is intentionally
  unguarded — litelib serializes wallet access internally via
  Arc<RwLock<LightWallet>>, so a C++ mutex is unnecessary and would defeat the
  sync/syncstatus concurrency the design relies on. syncLaunched_ -> atomic.

Tests: fake backend now returns the real init shapes (seed object for
create/restore, bare "OK" for open) and a new open-path case guards the
walletReady regression. Removed an unreliable alloc==freed leak assert from the
thread-bearing controller test (kept in the thread-free bridge test). Also fixed
a stray CMake indent and removed ~220MB of untracked build/debug scratch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-05 11:28:37 -05:00
co-authored by Claude Opus 4.8
parent 2daea67a1e
commit 043cdc7128
7 changed files with 76 additions and 25 deletions
+7 -7
View File
@@ -7,8 +7,6 @@
#include <cctype>
#include <utility>
#include <nlohmann/json.hpp>
namespace dragonx {
namespace wallet {
@@ -384,11 +382,13 @@ LiteWalletLifecycleResult LiteWalletLifecycleService::bridgeResult(
result.ok = true;
result.bridgeAccepted = true;
// The bridge already classifies "Error:"-prefixed responses as failures (ok=false).
// A successful init returns a JSON document (seed info for create, wallet info for
// open/restore); treat a well-formed JSON response as a genuinely ready wallet rather
// than discarding it. (Richer field extraction lands with the sync slice.)
result.walletReady = nlohmann::json::accept(bridgeCall.value);
// The bridge already classifies "Error:"-prefixed responses (and null/empty returns) as
// failures (ok=false), so reaching here means the backend genuinely succeeded. The success
// payloads are NOT uniformly JSON: create/restore return a seed object
// ({"seed":..,"birthday":..}), but open (litelib_initialize_existing) returns the bare
// string "OK". A JSON-validity test would therefore wrongly mark a successful open as
// not-ready, so treat any non-empty success response as a ready wallet.
result.walletReady = !bridgeCall.value.empty();
result.status = successStatus;
return result;
}