Refactor app services and stabilize refresh/UI flows

- Add refresh scheduler and network refresh service boundaries for typed
  refresh results, ordered RPC collectors, applicators, and price parsing.
- Add daemon lifecycle and wallet security workflow helpers while preserving
  App-owned command RPC, decrypt, cancellation, and UI handoff behavior.
- Split balance, console, mining, amount formatting, and async task logic into
  focused modules with expanded Phase 4 test coverage.
- Fix market price loading by triggering price refresh immediately, avoiding
  queue-pressure drops, tracking loading/error state, and adding translations.
- Polish send, explorer, peers, settings, theme/schema, and related tab UI.
- Replace checked-in generated language headers with build-generated resources.
- Document the cleanup audit, UI static-state guidance, and architecture updates.
This commit is contained in:
2026-04-29 12:47:57 -05:00
parent ee8a08e569
commit 9edab31728
95 changed files with 8776 additions and 37563 deletions

View File

@@ -0,0 +1,127 @@
#include "wallet_security_controller.h"
#include "../util/secure_vault.h"
#include <cctype>
#include <cstdio>
#include <utility>
namespace dragonx {
namespace services {
WalletSecurityController::~WalletSecurityController()
{
clearDeferredEncryption();
}
void WalletSecurityController::beginDeferredEncryption(std::string passphrase, std::string pin)
{
clearDeferredEncryption();
deferred_.passphrase = std::move(passphrase);
deferred_.pin = std::move(pin);
deferred_.pending = true;
deferred_.lastConnectAttempt = -10.0;
}
WalletSecurityController::DeferredEncryptionSnapshot WalletSecurityController::deferredEncryption() const
{
return {deferred_.passphrase, deferred_.pin};
}
bool WalletSecurityController::shouldAttemptDeferredConnect(double nowSeconds, double minIntervalSeconds)
{
if (!deferred_.pending) return false;
if (nowSeconds - deferred_.lastConnectAttempt < minIntervalSeconds) return false;
deferred_.lastConnectAttempt = nowSeconds;
return true;
}
void WalletSecurityController::clearDeferredEncryption()
{
secureClear(deferred_.passphrase);
secureClear(deferred_.pin);
deferred_.pending = false;
deferred_.lastConnectAttempt = -10.0;
}
WalletSecurityController::DeferredEncryptionResult WalletSecurityController::runDeferredEncryption(
DeferredEncryptionSnapshot request, RpcGateway& rpc, VaultGateway* vault)
{
DeferredEncryptionResult result;
result.pinProvided = !request.pin.empty();
std::string error;
if (!rpc.encryptWallet(request.passphrase, error)) {
result.error = error.empty() ? "encryptwallet failed" : error;
secureClear(request.passphrase);
secureClear(request.pin);
return result;
}
result.encrypted = true;
result.restartRequired = true;
if (result.pinProvided && vault) {
result.pinStored = vault->storePin(request.pin, request.passphrase);
}
secureClear(request.passphrase);
secureClear(request.pin);
return result;
}
WalletSecurityController::PinValidationResult WalletSecurityController::validatePinSetup(
const std::string& pin, const std::string& confirmation, bool allowEmpty, std::size_t minLength)
{
if (pin.empty() && confirmation.empty()) {
return allowEmpty
? PinValidationResult{true, PinValidationError::None, ""}
: PinValidationResult{false, PinValidationError::Empty, "PIN is required"};
}
if (pin != confirmation) {
return {false, PinValidationError::Mismatch, "PINs do not match"};
}
if (pin.size() < minLength) {
return {false, PinValidationError::TooShort, "PIN is too short"};
}
for (unsigned char c : pin) {
if (!std::isdigit(c)) {
return {false, PinValidationError::NonDigit, "PIN must contain only digits"};
}
}
return {true, PinValidationError::None, ""};
}
WalletSecurityController::KeyKind WalletSecurityController::classifyAddress(const std::string& address)
{
return !address.empty() && address[0] == 'z' ? KeyKind::Shielded : KeyKind::Transparent;
}
WalletSecurityController::KeyKind WalletSecurityController::classifyPrivateKey(const std::string& key)
{
return !key.empty() && key[0] == 's' ? KeyKind::Shielded : KeyKind::Transparent;
}
const char* WalletSecurityController::importSuccessMessage(KeyKind kind)
{
return kind == KeyKind::Shielded
? "Z-address key imported successfully. Wallet is rescanning."
: "T-address key imported successfully. Wallet is rescanning.";
}
std::string WalletSecurityController::decryptExportFileName(std::uint64_t timestampSeconds)
{
char buffer[64];
snprintf(buffer, sizeof(buffer), "obsidiandecryptexport%llu",
static_cast<unsigned long long>(timestampSeconds));
return std::string(buffer);
}
void WalletSecurityController::secureClear(std::string& value)
{
if (!value.empty()) {
util::SecureVault::secureZero(&value[0], value.size());
value.clear();
}
}
} // namespace services
} // namespace dragonx