diff options
Diffstat (limited to 'src/wallet/api')
-rw-r--r-- | src/wallet/api/wallet.cpp | 142 | ||||
-rw-r--r-- | src/wallet/api/wallet.h | 7 | ||||
-rw-r--r-- | src/wallet/api/wallet_manager.cpp | 57 | ||||
-rw-r--r-- | src/wallet/api/wallet_manager.h | 7 |
4 files changed, 185 insertions, 28 deletions
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 52ecc2e6a..9e40d2e02 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -197,6 +197,44 @@ bool Wallet::addressValid(const std::string &str, bool testnet) return get_account_integrated_address_from_str(address, has_payment_id, pid, testnet, str); } +bool Wallet::keyValid(const std::string &secret_key_string, const std::string &address_string, bool isViewKey, bool testnet, std::string &error) +{ + bool has_payment_id; + cryptonote::account_public_address address; + crypto::hash8 pid; + if(!get_account_integrated_address_from_str(address, has_payment_id, pid, testnet, address_string)) { + error = tr("Failed to parse address"); + return false; + } + + cryptonote::blobdata key_data; + if(!epee::string_tools::parse_hexstr_to_binbuff(secret_key_string, key_data) || key_data.size() != sizeof(crypto::secret_key)) + { + error = tr("Failed to parse key"); + return false; + } + crypto::secret_key key = *reinterpret_cast<const crypto::secret_key*>(key_data.data()); + + // check the key match the given address + crypto::public_key pkey; + if (!crypto::secret_key_to_public_key(key, pkey)) { + error = tr("failed to verify key"); + return false; + } + bool matchAddress = false; + if(isViewKey) + matchAddress = address.m_view_public_key == pkey; + else + matchAddress = address.m_spend_public_key == pkey; + + if(!matchAddress) { + error = tr("key does not match address"); + return false; + } + + return true; +} + std::string Wallet::paymentIdFromAddress(const std::string &str, bool testnet) { bool has_payment_id; @@ -337,6 +375,98 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas return true; } +bool WalletImpl::recoverFromKeys(const std::string &path, + const std::string &language, + const std::string &address_string, + const std::string &viewkey_string, + const std::string &spendkey_string) +{ + cryptonote::account_public_address address; + bool has_payment_id; + crypto::hash8 new_payment_id; + if(!get_account_integrated_address_from_str(address, has_payment_id, new_payment_id, m_wallet->testnet(), address_string)) + { + m_errorString = tr("failed to parse address"); + m_status = Status_Error; + return false; + } + + // parse optional spend key + crypto::secret_key spendkey; + bool has_spendkey = false; + if (!spendkey_string.empty()) { + cryptonote::blobdata spendkey_data; + if(!epee::string_tools::parse_hexstr_to_binbuff(spendkey_string, spendkey_data) || spendkey_data.size() != sizeof(crypto::secret_key)) + { + m_errorString = tr("failed to parse secret spend key"); + m_status = Status_Error; + return false; + } + has_spendkey = true; + spendkey = *reinterpret_cast<const crypto::secret_key*>(spendkey_data.data()); + } + + // parse view secret key + if (viewkey_string.empty()) { + m_errorString = tr("No view key supplied, cancelled"); + m_status = Status_Error; + return false; + } + cryptonote::blobdata viewkey_data; + if(!epee::string_tools::parse_hexstr_to_binbuff(viewkey_string, viewkey_data) || viewkey_data.size() != sizeof(crypto::secret_key)) + { + m_errorString = tr("failed to parse secret view key"); + m_status = Status_Error; + return false; + } + crypto::secret_key viewkey = *reinterpret_cast<const crypto::secret_key*>(viewkey_data.data()); + + // check the spend and view keys match the given address + crypto::public_key pkey; + if(has_spendkey) { + if (!crypto::secret_key_to_public_key(spendkey, pkey)) { + m_errorString = tr("failed to verify secret spend key"); + m_status = Status_Error; + return false; + } + if (address.m_spend_public_key != pkey) { + m_errorString = tr("spend key does not match address"); + m_status = Status_Error; + return false; + } + } + if (!crypto::secret_key_to_public_key(viewkey, pkey)) { + m_errorString = tr("failed to verify secret view key"); + m_status = Status_Error; + return false; + } + if (address.m_view_public_key != pkey) { + m_errorString = tr("view key does not match address"); + m_status = Status_Error; + return false; + } + + try + { + if (has_spendkey) { + m_wallet->generate(path, "", address, spendkey, viewkey); + LOG_PRINT_L1("Generated new wallet from keys"); + } + else { + m_wallet->generate(path, "", address, viewkey); + LOG_PRINT_L1("Generated new view only wallet from keys"); + } + + } + catch (const std::exception& e) { + m_errorString = string(tr("failed to generate new wallet: ")) + e.what(); + m_status = Status_Error; + return false; + } + return true; +} + + bool WalletImpl::open(const std::string &path, const std::string &password) { clearStatus(); @@ -516,12 +646,12 @@ string WalletImpl::keysFilename() const bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transaction_size_limit) { clearStatus(); - doInit(daemon_address, upper_transaction_size_limit); + if (!doInit(daemon_address, upper_transaction_size_limit)) + return false; bool result = this->refresh(); // enabling background refresh thread startRefresh(); return result; - } void WalletImpl::initAsync(const string &daemon_address, uint64_t upper_transaction_size_limit) @@ -1232,9 +1362,10 @@ bool WalletImpl::isNewWallet() const return !(blockChainHeight() > 1 || m_recoveringFromSeed || m_rebuildWalletCache) && !watchOnly(); } -void WalletImpl::doInit(const string &daemon_address, uint64_t upper_transaction_size_limit) +bool WalletImpl::doInit(const string &daemon_address, uint64_t upper_transaction_size_limit) { - m_wallet->init(daemon_address, upper_transaction_size_limit); + if (!m_wallet->init(daemon_address, upper_transaction_size_limit)) + return false; // in case new wallet, this will force fast-refresh (pulling hashes instead of blocks) // If daemon isn't synced a calculated block height will be used instead @@ -1253,8 +1384,7 @@ void WalletImpl::doInit(const string &daemon_address, uint64_t upper_transaction this->setTrustedDaemon(false); m_refreshIntervalMillis = DEFAULT_REMOTE_NODE_REFRESH_INTERVAL_MILLIS; } - - + return true; } bool WalletImpl::parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector<std::string> &unknown_parameters, std::string &error) diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index bee2342a2..7daf63e43 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -58,6 +58,11 @@ public: const std::string &language) const; bool open(const std::string &path, const std::string &password); bool recover(const std::string &path, const std::string &seed); + bool recoverFromKeys(const std::string &path, + const std::string &language, + const std::string &address_string, + const std::string &viewkey_string, + const std::string &spendkey_string = ""); bool close(); std::string seed() const; std::string getSeedLanguage() const; @@ -128,7 +133,7 @@ private: bool daemonSynced() const; void stopRefresh(); bool isNewWallet() const; - void doInit(const std::string &daemon_address, uint64_t upper_transaction_size_limit); + bool doInit(const std::string &daemon_address, uint64_t upper_transaction_size_limit); private: diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp index 904338a72..c761cc6d2 100644 --- a/src/wallet/api/wallet_manager.cpp +++ b/src/wallet/api/wallet_manager.cpp @@ -43,6 +43,15 @@ namespace epee { unsigned int g_test_dbg_lock_sleep = 0; } +namespace { + template<typename Request, typename Response> + bool connect_and_invoke(const std::string& address, const std::string& path, const Request& request, Response& response) + { + epee::net_utils::http::http_simple_client client{}; + return client.set_server(address) && epee::net_utils::invoke_http_json(path, request, response, client); + } +} + namespace Monero { Wallet *WalletManagerImpl::createWallet(const std::string &path, const std::string &password, @@ -72,6 +81,22 @@ Wallet *WalletManagerImpl::recoveryWallet(const std::string &path, const std::st return wallet; } +Wallet *WalletManagerImpl::createWalletFromKeys(const std::string &path, + const std::string &language, + bool testnet, + uint64_t restoreHeight, + const std::string &addressString, + const std::string &viewKeyString, + const std::string &spendKeyString) +{ + WalletImpl * wallet = new WalletImpl(testnet); + if(restoreHeight > 0){ + wallet->setRefreshFromBlockHeight(restoreHeight); + } + wallet->recoverFromKeys(path, language, addressString, viewKeyString, spendKeyString); + return wallet; +} + bool WalletManagerImpl::closeWallet(Wallet *wallet) { WalletImpl * wallet_ = dynamic_cast<WalletImpl*>(wallet); @@ -145,9 +170,7 @@ bool WalletManagerImpl::connected(uint32_t *version) const req_t.jsonrpc = "2.0"; req_t.id = epee::serialization::storage_entry(0); req_t.method = "get_version"; - epee::net_utils::http::http_simple_client http_client; - bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/json_rpc", req_t, resp_t, http_client); - if (!r) + if (!connect_and_invoke(m_daemonAddress, "/json_rpc", req_t, resp_t)) return false; if (version) @@ -193,8 +216,7 @@ bool WalletManagerImpl::checkPayment(const std::string &address_text, const std: cryptonote::COMMAND_RPC_GET_TRANSACTIONS::request req; cryptonote::COMMAND_RPC_GET_TRANSACTIONS::response res; req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid)); - epee::net_utils::http::http_simple_client http_client; - if (!epee::net_utils::invoke_http_json_remote_command2(daemon_address + "/gettransactions", req, res, http_client) || + if (!connect_and_invoke(m_daemonAddress, "/gettransactions", req, res) || (res.txs.size() != 1 && res.txs_as_hex.size() != 1)) { error = tr("failed to get transaction from daemon"); @@ -312,8 +334,7 @@ uint64_t WalletManagerImpl::blockchainHeight() const cryptonote::COMMAND_RPC_GET_INFO::request ireq; cryptonote::COMMAND_RPC_GET_INFO::response ires; - epee::net_utils::http::http_simple_client http_client; - if (!epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/getinfo", ireq, ires, http_client)) + if (!connect_and_invoke(m_daemonAddress, "/getinfo", ireq, ires)) return 0; return ires.height; } @@ -323,8 +344,7 @@ uint64_t WalletManagerImpl::blockchainTargetHeight() const cryptonote::COMMAND_RPC_GET_INFO::request ireq; cryptonote::COMMAND_RPC_GET_INFO::response ires; - epee::net_utils::http::http_simple_client http_client; - if (!epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/getinfo", ireq, ires, http_client)) + if (!connect_and_invoke(m_daemonAddress, "/getinfo", ireq, ires)) return 0; return ires.target_height >= ires.height ? ires.target_height : ires.height; } @@ -334,8 +354,7 @@ uint64_t WalletManagerImpl::networkDifficulty() const cryptonote::COMMAND_RPC_GET_INFO::request ireq; cryptonote::COMMAND_RPC_GET_INFO::response ires; - epee::net_utils::http::http_simple_client http_client; - if (!epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/getinfo", ireq, ires, http_client)) + if (!connect_and_invoke(m_daemonAddress, "/getinfo", ireq, ires)) return 0; return ires.difficulty; } @@ -346,7 +365,7 @@ double WalletManagerImpl::miningHashRate() const cryptonote::COMMAND_RPC_MINING_STATUS::response mres; epee::net_utils::http::http_simple_client http_client; - if (!epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/mining_status", mreq, mres, http_client)) + if (!connect_and_invoke(m_daemonAddress, "/mining_status", mreq, mres)) return 0.0; if (!mres.active) return 0.0; @@ -366,7 +385,7 @@ void WalletManagerImpl::hardForkInfo(uint8_t &version, uint64_t &earliest_height req_t.id = epee::serialization::storage_entry(0); req_t.method = "hard_fork_info"; req_t.params.version = 0; - bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/json_rpc", req_t, resp_t, http_client); + bool r = connect_and_invoke(m_daemonAddress, "/json_rpc", req_t, resp_t); if (!r || resp_t.result.status != CORE_RPC_STATUS_OK) return; version = resp_t.result.version; @@ -378,8 +397,7 @@ uint64_t WalletManagerImpl::blockTarget() const cryptonote::COMMAND_RPC_GET_INFO::request ireq; cryptonote::COMMAND_RPC_GET_INFO::response ires; - epee::net_utils::http::http_simple_client http_client; - if (!epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/getinfo", ireq, ires, http_client)) + if (!connect_and_invoke(m_daemonAddress, "/getinfo", ireq, ires)) return 0; return ires.target; } @@ -389,8 +407,7 @@ bool WalletManagerImpl::isMining() const cryptonote::COMMAND_RPC_MINING_STATUS::request mreq; cryptonote::COMMAND_RPC_MINING_STATUS::response mres; - epee::net_utils::http::http_simple_client http_client; - if (!epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/mining_status", mreq, mres, http_client)) + if (!connect_and_invoke(m_daemonAddress, "/mining_status", mreq, mres)) return false; return mres.active; } @@ -403,8 +420,7 @@ bool WalletManagerImpl::startMining(const std::string &address, uint32_t threads mreq.miner_address = address; mreq.threads_count = threads; - epee::net_utils::http::http_simple_client http_client; - if (!epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/start_mining", mreq, mres, http_client)) + if (!connect_and_invoke(m_daemonAddress, "/start_mining", mreq, mres)) return false; return mres.status == CORE_RPC_STATUS_OK; } @@ -414,8 +430,7 @@ bool WalletManagerImpl::stopMining() cryptonote::COMMAND_RPC_STOP_MINING::request mreq; cryptonote::COMMAND_RPC_STOP_MINING::response mres; - epee::net_utils::http::http_simple_client http_client; - if (!epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/stop_mining", mreq, mres, http_client)) + if (!connect_and_invoke(m_daemonAddress, "/stop_mining", mreq, mres)) return false; return mres.status == CORE_RPC_STATUS_OK; } diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h index ca9570254..ce9b70e96 100644 --- a/src/wallet/api/wallet_manager.h +++ b/src/wallet/api/wallet_manager.h @@ -41,6 +41,13 @@ public: const std::string &language, bool testnet); Wallet * openWallet(const std::string &path, const std::string &password, bool testnet); virtual Wallet * recoveryWallet(const std::string &path, const std::string &memo, bool testnet, uint64_t restoreHeight); + virtual Wallet * createWalletFromKeys(const std::string &path, + const std::string &language, + bool testnet, + uint64_t restoreHeight, + const std::string &addressString, + const std::string &viewKeyString, + const std::string &spendKeyString = ""); virtual bool closeWallet(Wallet *wallet); bool walletExists(const std::string &path); std::vector<std::string> findWallets(const std::string &path); |