fix(wallet-switch): close gaps found verifying clusters A/B/C
Adversarial verification of the audit fixes found real gaps in them: - HIGH throw-safety: the switch worker and the encryption-restart worker set daemon_restarting_=true but reset it only on their normal/early-return paths — a throw from stop/startEmbeddedDaemon left the flag stuck true, wedging reconnect and every future switch/rescan/encryption. Both now reset it on all paths (try/catch); a throw during a switch is treated as a failed switch and triggers the revert. - HIGH residual chat leak: resetChatSession() cleared the flags but an already- posted z_exportmnemonic worker job still held wallet A's secret, and its completion callback (guarded only by isLocked(), false for an unencrypted wallet) would provision A's identity under B. Add a chat_session_generation_ epoch bumped on every wallet change; the fetch captures it and its callback discards the (previous-wallet) secret if the epoch no longer matches. - LOW vault-scope collision: the per-wallet vault tag was a lossy char-substitution (two distinct files could map to one vault). Append an 8-hex FNV-1a of the raw filename so distinct wallets never share a vault. +unit test. - LOW seed-adopt: removeVault() on adopt so the legacy wallet's PIN passphrase isn't left associated with the new seed wallet (same file name). - LOW: clear lock_unlock_in_progress_ on switch too. Deferred (documented): the 1.5s start grace can't catch a wallet that fails LATE in daemon init (the existing crash-wedge detection still applies); beginShutdown's join of the switch task can briefly freeze the UI during quit (necessary to avoid orphaning the daemon). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
#include "data/transaction_history_cache.h"
|
||||
#include "data/address_book.h"
|
||||
#include "data/wallet_index.h"
|
||||
#include "util/secure_vault.h"
|
||||
#include "daemon/lifecycle_adapters.h"
|
||||
#include "data/wallet_state.h"
|
||||
#include "rpc/connection.h"
|
||||
@@ -2139,6 +2140,34 @@ void testOperationStatusPollParsing()
|
||||
EXPECT_TRUE(malformed.staleOpids.empty());
|
||||
}
|
||||
|
||||
void testSecureVaultScope()
|
||||
{
|
||||
using dragonx::util::SecureVault;
|
||||
auto endsWith = [](const std::string& s, const std::string& suf) {
|
||||
return s.size() >= suf.size() && s.compare(s.size() - suf.size(), suf.size(), suf) == 0;
|
||||
};
|
||||
|
||||
// Default wallet (empty or "wallet.dat") keeps the legacy global vault.dat for back-compat.
|
||||
EXPECT_TRUE(endsWith(SecureVault("").getVaultPath(), "vault.dat"));
|
||||
EXPECT_TRUE(endsWith(SecureVault("wallet.dat").getVaultPath(), "vault.dat"));
|
||||
|
||||
// A non-default wallet gets its own, distinct vault (not the legacy path).
|
||||
SecureVault vb("wallet-savings.dat");
|
||||
const std::string pb = vb.getVaultPath();
|
||||
EXPECT_TRUE(pb.find("vault-") != std::string::npos);
|
||||
EXPECT_TRUE(pb != SecureVault("").getVaultPath());
|
||||
EXPECT_TRUE(pb != SecureVault("wallet-cold.dat").getVaultPath());
|
||||
|
||||
// The FNV suffix disambiguates sanitize-colliding names, so distinct files never share a vault.
|
||||
EXPECT_TRUE(SecureVault("wallet foo.dat").getVaultPath() != SecureVault("wallet_foo.dat").getVaultPath());
|
||||
|
||||
// Re-scoping moves the path; scoping back to the default returns to vault.dat.
|
||||
vb.setWalletScope("wallet-cold.dat");
|
||||
EXPECT_TRUE(vb.getVaultPath() == SecureVault("wallet-cold.dat").getVaultPath());
|
||||
vb.setWalletScope("wallet.dat");
|
||||
EXPECT_TRUE(endsWith(vb.getVaultPath(), "vault.dat"));
|
||||
}
|
||||
|
||||
void testWalletSecurityController()
|
||||
{
|
||||
using dragonx::services::WalletSecurityController;
|
||||
@@ -6390,6 +6419,7 @@ int main()
|
||||
testNetworkRefreshRpcCollectors();
|
||||
testNetworkRefreshResultModels();
|
||||
testOperationStatusPollParsing();
|
||||
testSecureVaultScope();
|
||||
testWalletSecurityController();
|
||||
testWalletSecurityWorkflow();
|
||||
testWalletSecurityWorkflowExecutor();
|
||||
|
||||
Reference in New Issue
Block a user