#include "wallet_security_controller.h" #include "../util/secure_vault.h" #include #include #include 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(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