fix(sweep): keep the UI sweep away from real wallet data
The full UI sweep (dev builds only) ran its demo surfaces against the
real profile. Its teardown deleted wallet-{cold,trading,mining,donations,
2023,payroll}.dat from the real datadir, it created zero-filled wallet
files and picker-demo/extra-wallets folders, its demo wallet-index upsert
re-minted the active wallet's scopeId (hiding "w:"-scoped contacts), the
Contacts tab could re-attach legacy-scoped contacts to such a throwaway
id in addressbook.json, and it persisted the demo active wallet file and
Mining pool worker.
- Preflight: a full sweep is refused (toast + log line) while a real
workflow is in flight: a pending seed_migration_* setting or open
migrate dialog, a wallet switch, an encryption/import workflow, an
encrypt/PIN/lock operation, the seed-backup dialog, or a bootstrap.
The DRAGONX_FULL_SWEEP hook then exits as for an empty catalog.
- Persistence latches: AddressBook (snapshot on the first sweepBegin,
save/load latched while a demo-contacts surface is shown), WalletIndex
and Settings (active wallet file, contacts view mode, pool URL/worker)
for the whole sweep. Settings::sweepEnd() is the last statement of
clearDemoWalletData and flushes once only if a save was suppressed; a
quit mid-sweep writes nothing to the profile (the 0700 sandbox, with
zero-filled demo files only, may stay in the temp dir).
- Scope ids: during a full sweep activeWalletScopeId() returns the
persisted id or "" and never mints one, so the Contacts tab cannot
move legacy-scoped contacts to a throwaway id. The only address-book
write a sweep can still cause is the one-time legacy re-attach to the
wallet's persisted id, which opening Contacts does anyway.
- Sandbox: demo wallet files and folders go to a fresh random 0700 dir
under the temp dir (exclusive create, a pre-existing path or symlink
is refused), removed at sweep end. The teardown that deleted those six
wallet files is gone.
- Cleanup: the migrate-to-seed state, wizard phase, demo chat
conversations and a fabricated demo chat identity are reset at sweep
end; the seed-backup surface always shows the demo phrase and a real
z_exportmnemonic result is dropped while the sweep runs.
- i18n: one new key (screenshot_sweep_refused) in i18n.cpp and the 8
language files.
Tests: the address book snapshots only on the first sweepBegin, keeps
addressbook.json byte-identical while latched and restores the real
book; the wallet index keeps wallets.json and the real scope id, also
with the background writer attached; Settings restores the latched
values and flushes once only when a save was suppressed; the sandbox
helper refuses a pre-existing path or symlink and removes only a
prefixed dir, never a symlink's target.
Release note: v2.0.x UI sweeps could delete wallet-{cold,trading,mining,
donations,2023,payroll}.dat from the data directory and re-scope
contacts; this cannot be undone automatically.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+20
-3
@@ -130,10 +130,25 @@ public:
|
||||
std::uint64_t revision() const { return revision_; }
|
||||
|
||||
/**
|
||||
* @brief UI-sweep ONLY: replace the in-memory entries WITHOUT persisting to disk, so the sweep can
|
||||
* seed demo contacts and restore the real book without a disk write. Do not use outside the sweep.
|
||||
* @brief UI-sweep ONLY: show `demo` instead of the real book. The first call snapshots the real
|
||||
* entries; later calls (the sweep re-runs its setup every frame) only swap the demo list. While
|
||||
* active, save() and load() return true without touching disk or the snapshot, so nothing (an
|
||||
* add/update/remove, reattachLegacyScopes) can persist demo contacts. Do not use outside the sweep.
|
||||
*/
|
||||
void sweepSetEntries(std::vector<AddressBookEntry> e) { entries_ = std::move(e); ++revision_; }
|
||||
void sweepBegin(std::vector<AddressBookEntry> demo) {
|
||||
if (!sweep_active_) { sweep_backup_ = std::move(entries_); sweep_active_ = true; }
|
||||
entries_ = std::move(demo);
|
||||
++revision_;
|
||||
}
|
||||
/** @brief UI-sweep ONLY: put the real book back (no disk write). Idempotent. */
|
||||
void sweepEnd() {
|
||||
if (!sweep_active_) return;
|
||||
entries_ = std::move(sweep_backup_);
|
||||
sweep_backup_.clear();
|
||||
sweep_active_ = false;
|
||||
++revision_;
|
||||
}
|
||||
bool sweepActive() const { return sweep_active_; }
|
||||
|
||||
/**
|
||||
* @brief Check if empty
|
||||
@@ -144,6 +159,8 @@ private:
|
||||
std::vector<AddressBookEntry> entries_;
|
||||
std::uint64_t revision_ = 0;
|
||||
std::string file_path_;
|
||||
std::vector<AddressBookEntry> sweep_backup_; // the real book while a UI sweep shows demo contacts
|
||||
bool sweep_active_ = false;
|
||||
};
|
||||
|
||||
} // namespace data
|
||||
|
||||
Reference in New Issue
Block a user