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:
127
src/services/wallet_security_controller.cpp
Normal file
127
src/services/wallet_security_controller.cpp
Normal 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
|
||||
Reference in New Issue
Block a user