#pragma once #include #include #include namespace dragonx { namespace services { class WalletSecurityController { public: enum class PinValidationError { None, Empty, Mismatch, TooShort, NonDigit }; struct PinValidationResult { bool ok = false; PinValidationError error = PinValidationError::None; const char* message = ""; }; struct DeferredEncryptionSnapshot { std::string passphrase; std::string pin; }; class RpcGateway { public: virtual ~RpcGateway() = default; virtual bool encryptWallet(const std::string& passphrase, std::string& error) = 0; virtual bool unlockWallet(const std::string& passphrase, int timeoutSeconds, std::string& error) = 0; virtual bool exportWallet(const std::string& fileName, long timeoutSeconds, std::string& error) = 0; virtual bool importWallet(const std::string& filePath, long timeoutSeconds, std::string& error) = 0; }; class VaultGateway { public: virtual ~VaultGateway() = default; virtual bool storePin(const std::string& pin, const std::string& passphrase) = 0; }; enum class KeyKind { Transparent, Shielded }; struct DeferredEncryptionResult { bool encrypted = false; bool pinProvided = false; bool pinStored = false; bool restartRequired = false; std::string error; }; ~WalletSecurityController(); void beginDeferredEncryption(std::string passphrase, std::string pin = {}); bool hasDeferredEncryption() const { return deferred_.pending; } DeferredEncryptionSnapshot deferredEncryption() const; bool shouldAttemptDeferredConnect(double nowSeconds, double minIntervalSeconds = 3.0); void clearDeferredEncryption(); DeferredEncryptionResult runDeferredEncryption(DeferredEncryptionSnapshot request, RpcGateway& rpc, VaultGateway* vault); static PinValidationResult validatePinSetup(const std::string& pin, const std::string& confirmation, bool allowEmpty = false, std::size_t minLength = 4); static KeyKind classifyAddress(const std::string& address); static KeyKind classifyPrivateKey(const std::string& key); // True if `key` is a shielded viewing key (extended full viewing key, "zxview…" — watch-only). static bool isViewingKey(const std::string& key); // True if `key` looks like a recognized Z (Sapling/Sprout spending) or T (WIF) private key. static bool isRecognizedPrivateKey(const std::string& key); // As above, but also accepts a recognized shielded viewing key — the import dialog auto-detects // both, so this is the single source of truth for its indicator AND its submit guard. static bool isRecognizedImportKey(const std::string& key); static const char* importSuccessMessage(KeyKind kind); static std::string decryptExportFileName(std::uint64_t timestampSeconds); static void secureClear(std::string& value); private: struct DeferredEncryptionState { std::string passphrase; std::string pin; bool pending = false; double lastConnectAttempt = -10.0; }; DeferredEncryptionState deferred_; }; } // namespace services } // namespace dragonx