Added recover from keys, and more bug fixes

This commit is contained in:
Lee Clagett
2025-04-01 21:59:25 -04:00
parent 5a97a0963a
commit f3d06bfe0e
7 changed files with 104 additions and 28 deletions
+1 -1
View File
@@ -1375,4 +1375,4 @@ struct WalletManagerFactory
static void setLogCategories(const std::string &categories);
};
}
} // lwsf
+14 -7
View File
@@ -447,8 +447,8 @@ namespace lwsf { namespace internal { namespace backend
void merge_subaddrs(account& self, const epee::span<const rpc::subaddrs> subaddrs)
{
/* This will purge subaddresses that the server somehow no longer claims
as being valid. The existing info per subaddress is moved/preserved. */
/* Purge subaccounts that do not have info (label) and are not mentioned
by the server. */
std::map<std::uint32_t, sub_account> subaccounts;
subaccounts.swap(self.subaccounts);
@@ -456,6 +456,17 @@ namespace lwsf { namespace internal { namespace backend
// Never remove special {0,0} account
self.subaccounts[0].minor[0] = std::move(subaccounts[0].minor[0]);
// Keep all subaccounts with a info
for (auto& account : subaccounts)
{
for (auto& subaccount : account.second.minor)
{
if (subaccount.second.preserve())
self.subaccounts[account.first].minor[subaccount.first] = std::move(subaccount.second);
}
}
// Keep all subaccounts mentioned by server
for (const auto& subaddr : subaddrs)
{
auto& account = self.subaccounts[subaddr.key];
@@ -463,11 +474,7 @@ namespace lwsf { namespace internal { namespace backend
for (const auto& minors : subaddr.value)
{
for (std::uint32_t minor = std::get<0>(minors); minor < std::uint64_t(std::get<1>(minors)) + 1; ++minor)
{
auto elem = account.minor.try_emplace(minor);
if (elem.second && (subaddr.key || minor))
elem.first->second = std::move(old.minor[minor]);
}
account.minor.try_emplace(minor);
}
}
}
+4 -2
View File
@@ -77,6 +77,8 @@ namespace lwsf { namespace internal { namespace backend
struct subaddress
{
std::string label;
bool preserve() const noexcept { return !label.empty(); }
};
WIRE_DECLARE_OBJECT(subaddress);
@@ -128,9 +130,9 @@ namespace lwsf { namespace internal { namespace backend
receives(),
description(),
timestamp(),
height(),
amount(0),
fee(0),
height(),
unlock_time(0),
direction(Monero::TransactionInfo::Direction_Out),
payment_id(),
@@ -154,9 +156,9 @@ namespace lwsf { namespace internal { namespace backend
boost::container::flat_map<crypto::public_key, transfer_in, memory> receives; //!< Key is output pub
std::string description;
std::optional<std::time_t> timestamp;
std::optional<std::uint64_t> height;
std::uint64_t amount;
std::uint64_t fee;
std::optional<std::uint64_t> height;
std::uint64_t unlock_time;
Monero::TransactionInfo::Direction direction;
std::variant<rpc::empty, crypto::hash8, crypto::hash> payment_id;
+11 -6
View File
@@ -76,7 +76,7 @@ namespace lwsf { namespace internal
std::string transaction_info::description() const
{
const boost::lock_guard<boost::mutex> lock{wallet_->sync};
return data_->description;
return data_->description; // this can change outside of refresh func
}
std::set<std::uint32_t> transaction_info::subaddrIndex() const
@@ -84,11 +84,16 @@ namespace lwsf { namespace internal
std::set<std::uint32_t> out;
const std::uint32_t major = subaddrAccount();
for (const auto& receive : data_->receives)
out.insert(receive.second.recipient.min_i);
for (const auto& spend : data_->spends)
out.insert(spend.second.sender.min_i);
if (direction() == Direction_In)
{
for (const auto& receive : data_->receives)
out.insert(receive.second.recipient.min_i);
}
else
{
for (const auto& spend : data_->spends)
out.insert(spend.second.sender.min_i);
}
return out;
}
+55
View File
@@ -585,6 +585,61 @@ namespace lwsf { namespace internal
load_wallet(data_->primary, recovery, nettype, false);
}
wallet::wallet(from_keys, const Monero::NetworkType nettype, std::string filename, std::string password, const std::uint64_t kdf_rounds, const std::string& address_string, const std::string& view_key, const std::string& spend_key)
: data_(std::make_shared<backend::wallet>()),
addressbook_(),
history_(),
subaddresses_(),
subaddress_minor_(),
filename_(std::move(filename)),
password_(std::move(password)),
exception_error_(),
status_(),
thread_(),
iterations_(kdf_rounds),
mixin_(config::mixin_default),
refresh_interval_(config::refresh_interval),
refresh_notify_(),
error_sync_(),
refresh_sync_(),
thread_sync_(),
thread_state_(state::stop),
mandatory_refresh_(false)
{
if (sodium_init() < 0)
throw std::runtime_error{"Failed to initialize libsodium"};
data_->primary.generated_locally = false;
data_->primary.type = nettype;
if (!epee::from_hex::to_buffer(epee::as_mut_byte_span(unwrap(unwrap(data_->primary.view.sec))), view_key))
{
exception_error_ = "view_key contained invalid hex";
return;
}
if (!crypto::secret_key_to_public_key(data_->primary.view.sec, data_->primary.view.pub))
{
exception_error_ = "view_pub could not be computed";
return;
}
crypto::secret_key spend_sec;
if (!epee::from_hex::to_buffer(epee::as_mut_byte_span(unwrap(unwrap(data_->primary.spend.sec))), spend_key))
{
exception_error_ = "spend_key contained invalid hex";
return;
}
if (!crypto::secret_key_to_public_key(data_->primary.spend.sec, data_->primary.spend.pub))
{
exception_error_ = "spend_pub could not be computed";
return;
}
if (data_->get_spend_address({0, 0}) != address_string)
exception_error_ = "view_key, spend_key, and address_string do not match";
}
wallet::~wallet() { stop_refresh_loop(); }
std::string wallet::seed(const std::string& seed_offset) const
+4 -3
View File
@@ -34,9 +34,10 @@
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <cstdint>
#include <memory>
#include <string>
#include "cryptonote_basic/account.h" // monero/src
#include <system_error>
#include "net/http_client.h" // monero/contrib/epee/include
#include "wallet/api/wallet2_api.h" // monero/src
@@ -89,8 +90,8 @@ namespace internal
wallet(create, Monero::NetworkType nettype, std::string filename, std::string password, std::uint64_t kdf_rounds);
wallet(open, Monero::NetworkType nettpe, std::string filename, std::string password, std::uint64_t kdf_rounds);
wallet(from_mnemonic, Monero::NetworkType nettype, std::string path, std::string password, std::uint64_t kdf_rounds, const std::string& mnemonic, const std::string& seed_offset);
wallet(from_keys, Monero::NetworkType nettype, std::string path, std::string password, std::uint64_t kdf_rounds, const std::string& mnemonic, const std::string& seed_offset);
wallet(from_mnemonic, Monero::NetworkType nettype, std::string filename, std::string password, std::uint64_t kdf_rounds, const std::string& mnemonic, const std::string& seed_offset);
wallet(from_keys, Monero::NetworkType nettype, std::string filename, std::string password, std::uint64_t kdf_rounds, const std::string& address_string, const std::string& view_key, const std::string& spend_key);
wallet(const wallet&) = delete;
wallet(wallet&&) = delete;
+15 -9
View File
@@ -28,11 +28,11 @@
#include "lws_frontend.h"
#include <boost/utility/string_ref.hpp>
#include <chrono>
#include <filesystem>
#include <memory>
#include <string>
#include <string_view>
#include <system_error>
#include "backend.h"
#include "common/dns_utils.h" // monero/src
@@ -178,7 +178,11 @@ namespace lwsf
const std::string &spendKeyString,
uint64_t kdf_rounds) override
{
//! \TODO Complete
auto out = std::make_unique<wallet>(
wallet::from_keys{}, nettype, path, password, kdf_rounds, addressString, viewKeyString, spendKeyString
);
out->setRefreshFromBlockHeight(restoreHeight);
return out.release();
}
/*!
@@ -201,7 +205,7 @@ namespace lwsf
const std::string &viewKeyString,
const std::string &spendKeyString) override
{
//! \TODO Complete
return createWalletFromKeys(path, "", language, nettype, restoreHeight, addressString, viewKeyString, spendKeyString, 1);
}
/*!
@@ -252,7 +256,7 @@ namespace lwsf
*/
bool walletExists(const std::string &path) override
{
return lwsf::internal::wallet::is_wallet_file(path);
return wallet::is_wallet_file(path);
}
/*!
@@ -269,7 +273,7 @@ namespace lwsf
*/
bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool, uint64_t) const override
{
lwsf::internal::wallet::verify_password(keys_file_name, password);
return wallet::verify_password(keys_file_name, password);
}
/*!
@@ -294,7 +298,7 @@ namespace lwsf
*/
std::vector<std::string> findWallets(const std::string &path) override
{
return lwsf::internal::wallet::find(path);
return wallet::find(path);
}
std::string errorString() const override { return error_; }
@@ -355,21 +359,23 @@ namespace lwsf
std::string resolveOpenAlias(const std::string &address, bool &dnssec_valid) const override
{
const boost::string_ref prefix{"oa1:xmr "};
static constexpr const std::string_view prefix{"oa1:xmr "};
std::string real_address =
tools::DNSResolver::instance().get_dns_format_from_oa_address(address);
bool dnssec_available = false;
std::vector<std::string> records =
tools::DNSResolver::instance().get_txt_record(real_address, dnssec_available, dnssec_valid);
for (boost::string_ref record : records)
for (std::string_view record : records)
{
if (record.starts_with(prefix))
if (record.substr(0, prefix.size()) == prefix)
{
record = record.substr(prefix.size());
return std::string{record.data(), record.size()};
}
}
return {};
}
//! checks for an update and returns version, hash and url