Wallet::store_to(path, password) implemented;
This commit is contained in:
parent
19fcc74912
commit
62606f11f5
|
@ -1461,6 +1461,78 @@ void wallet2::store()
|
||||||
THROW_WALLET_EXCEPTION_IF(e, error::file_save_error, m_wallet_file, e);
|
THROW_WALLET_EXCEPTION_IF(e, error::file_save_error, m_wallet_file, e);
|
||||||
boost::filesystem::remove(old_file);
|
boost::filesystem::remove(old_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wallet2::store_to(const std::string &path, const std::string &password)
|
||||||
|
{
|
||||||
|
// TODO: merge it with wallet2::store() function
|
||||||
|
|
||||||
|
// check if we want to store to directory which doesn't exists yet
|
||||||
|
boost::filesystem::path parent_path = boost::filesystem::path(path).parent_path();
|
||||||
|
|
||||||
|
// if path is not exists, try to create it
|
||||||
|
if (!parent_path.empty() && !boost::filesystem::exists(parent_path)) {
|
||||||
|
boost::system::error_code ec;
|
||||||
|
if (!boost::filesystem::create_directories(parent_path, ec)) {
|
||||||
|
throw std::logic_error(ec.message());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::stringstream oss;
|
||||||
|
boost::archive::binary_oarchive ar(oss);
|
||||||
|
ar << *this;
|
||||||
|
|
||||||
|
wallet2::cache_file_data cache_file_data = boost::value_initialized<wallet2::cache_file_data>();
|
||||||
|
cache_file_data.cache_data = oss.str();
|
||||||
|
crypto::chacha8_key key;
|
||||||
|
generate_chacha8_key_from_secret_keys(key);
|
||||||
|
std::string cipher;
|
||||||
|
cipher.resize(cache_file_data.cache_data.size());
|
||||||
|
cache_file_data.iv = crypto::rand<crypto::chacha8_iv>();
|
||||||
|
crypto::chacha8(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cipher[0]);
|
||||||
|
cache_file_data.cache_data = cipher;
|
||||||
|
|
||||||
|
|
||||||
|
const std::string new_file = path;
|
||||||
|
const std::string old_file = m_wallet_file;
|
||||||
|
const std::string old_keys_file = m_keys_file;
|
||||||
|
const std::string old_address_file = m_wallet_file + ".address.txt";
|
||||||
|
|
||||||
|
// save to new file
|
||||||
|
std::ofstream ostr;
|
||||||
|
ostr.open(new_file, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
|
||||||
|
binary_archive<true> oar(ostr);
|
||||||
|
bool success = ::serialization::serialize(oar, cache_file_data);
|
||||||
|
ostr.close();
|
||||||
|
THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file);
|
||||||
|
|
||||||
|
// save keys to the new file
|
||||||
|
// if we here, main wallet file is saved and we only need to save keys and address files
|
||||||
|
prepare_file_names(path);
|
||||||
|
store_keys(m_keys_file, password, false);
|
||||||
|
|
||||||
|
// save address to the new file
|
||||||
|
const std::string address_file = m_wallet_file + ".address.txt";
|
||||||
|
bool r = file_io_utils::save_string_to_file(address_file, m_account.get_public_address_str(m_testnet));
|
||||||
|
THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_wallet_file);
|
||||||
|
|
||||||
|
|
||||||
|
// remove old wallet file
|
||||||
|
r = boost::filesystem::remove(old_file);
|
||||||
|
if (!r) {
|
||||||
|
LOG_ERROR("error removing file: " << old_file);
|
||||||
|
}
|
||||||
|
// remove old keys file
|
||||||
|
r = boost::filesystem::remove(old_keys_file);
|
||||||
|
if (!r) {
|
||||||
|
LOG_ERROR("error removing file: " << old_keys_file);
|
||||||
|
}
|
||||||
|
// remove old address file
|
||||||
|
r = boost::filesystem::remove(old_address_file);
|
||||||
|
if (!r) {
|
||||||
|
LOG_ERROR("error removing file: " << old_address_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
uint64_t wallet2::unlocked_balance() const
|
uint64_t wallet2::unlocked_balance() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -212,6 +212,12 @@ namespace tools
|
||||||
void write_watch_only_wallet(const std::string& wallet_name, const std::string& password);
|
void write_watch_only_wallet(const std::string& wallet_name, const std::string& password);
|
||||||
void load(const std::string& wallet, const std::string& password);
|
void load(const std::string& wallet, const std::string& password);
|
||||||
void store();
|
void store();
|
||||||
|
/*!
|
||||||
|
* \brief store_to - stores wallet to another file(s), deleting old ones
|
||||||
|
* \param path - path to the wallet file (keys and address filenames will be generated based on this filename)
|
||||||
|
* \param password - password to protect new wallet (TODO: probably better save the password in the wallet object?)
|
||||||
|
*/
|
||||||
|
void store_to(const std::string &path, const std::string &password);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief verifies given password is correct for default wallet keys file
|
* \brief verifies given password is correct for default wallet keys file
|
||||||
|
|
|
@ -69,6 +69,7 @@ public:
|
||||||
std::string errorString() const;
|
std::string errorString() const;
|
||||||
bool setPassword(const std::string &password);
|
bool setPassword(const std::string &password);
|
||||||
std::string address() const;
|
std::string address() const;
|
||||||
|
bool store(const std::string &path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void clearStatus();
|
void clearStatus();
|
||||||
|
@ -78,7 +79,7 @@ private:
|
||||||
tools::wallet2 * m_wallet;
|
tools::wallet2 * m_wallet;
|
||||||
int m_status;
|
int m_status;
|
||||||
std::string m_errorString;
|
std::string m_errorString;
|
||||||
|
std::string m_password;
|
||||||
};
|
};
|
||||||
|
|
||||||
WalletImpl::WalletImpl()
|
WalletImpl::WalletImpl()
|
||||||
|
@ -118,34 +119,37 @@ bool WalletImpl::create(const std::string &path, const std::string &password, co
|
||||||
crypto::secret_key recovery_val, secret_key;
|
crypto::secret_key recovery_val, secret_key;
|
||||||
try {
|
try {
|
||||||
recovery_val = m_wallet->generate(path, password, secret_key, false, false);
|
recovery_val = m_wallet->generate(path, password, secret_key, false, false);
|
||||||
|
m_password = password;
|
||||||
|
m_status = Status_Ok;
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
LOG_ERROR("Error creating wallet: " << e.what());
|
LOG_ERROR("Error creating wallet: " << e.what());
|
||||||
m_status = Status_Error;
|
m_status = Status_Error;
|
||||||
m_errorString = e.what();
|
m_errorString = e.what();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WalletImpl::open(const std::string &path, const std::string &password)
|
bool WalletImpl::open(const std::string &path, const std::string &password)
|
||||||
{
|
{
|
||||||
clearStatus();
|
clearStatus();
|
||||||
bool result = false;
|
|
||||||
try {
|
try {
|
||||||
// TODO: handle "deprecated"
|
// TODO: handle "deprecated"
|
||||||
m_wallet->load(path, password);
|
m_wallet->load(path, password);
|
||||||
result = true;
|
|
||||||
|
m_password = password;
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
LOG_ERROR("Error opening wallet: " << e.what());
|
LOG_ERROR("Error opening wallet: " << e.what());
|
||||||
m_status = Status_Error;
|
m_status = Status_Error;
|
||||||
m_errorString = e.what();
|
m_errorString = e.what();
|
||||||
}
|
}
|
||||||
return result;
|
return m_status == Status_Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WalletImpl::recover(const std::string &path, const std::string &seed)
|
bool WalletImpl::recover(const std::string &path, const std::string &seed)
|
||||||
{
|
{
|
||||||
bool result = false;
|
clearStatus();
|
||||||
m_errorString.clear();
|
m_errorString.clear();
|
||||||
if (seed.empty()) {
|
if (seed.empty()) {
|
||||||
m_errorString = "Electrum seed is empty";
|
m_errorString = "Electrum seed is empty";
|
||||||
|
@ -162,23 +166,20 @@ bool WalletImpl::recover(const std::string &path, const std::string &seed)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
m_wallet->set_seed_language(old_language);
|
m_wallet->set_seed_language(old_language);
|
||||||
m_wallet->generate(path, "", recovery_key, true, false);
|
m_wallet->generate(path, "", recovery_key, true, false);
|
||||||
// TODO: wallet->init(daemon_address);
|
// TODO: wallet->init(daemon_address);
|
||||||
m_status = Status_Ok;
|
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
m_status = Status_Error;
|
m_status = Status_Error;
|
||||||
m_errorString = e.what();
|
m_errorString = e.what();
|
||||||
|
|
||||||
}
|
}
|
||||||
result = m_status == Status_Ok;
|
return m_status == Status_Ok;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WalletImpl::close()
|
bool WalletImpl::close()
|
||||||
{
|
{
|
||||||
|
clearStatus();
|
||||||
bool result = false;
|
bool result = false;
|
||||||
try {
|
try {
|
||||||
m_wallet->store();
|
m_wallet->store();
|
||||||
|
@ -222,16 +223,15 @@ std::string WalletImpl::errorString() const
|
||||||
|
|
||||||
bool WalletImpl::setPassword(const std::string &password)
|
bool WalletImpl::setPassword(const std::string &password)
|
||||||
{
|
{
|
||||||
bool result = false;
|
clearStatus();
|
||||||
try {
|
try {
|
||||||
m_wallet->rewrite(m_wallet->get_wallet_file(), password);
|
m_wallet->rewrite(m_wallet->get_wallet_file(), password);
|
||||||
result = true;
|
m_password = password;
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
result = false;
|
|
||||||
m_status = Status_Error;
|
m_status = Status_Error;
|
||||||
m_errorString = e.what();
|
m_errorString = e.what();
|
||||||
}
|
}
|
||||||
return result;
|
return m_status == Status_Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string WalletImpl::address() const
|
std::string WalletImpl::address() const
|
||||||
|
@ -239,6 +239,24 @@ std::string WalletImpl::address() const
|
||||||
return m_wallet->get_account().get_public_address_str(m_wallet->testnet());
|
return m_wallet->get_account().get_public_address_str(m_wallet->testnet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WalletImpl::store(const std::string &path)
|
||||||
|
{
|
||||||
|
clearStatus();
|
||||||
|
try {
|
||||||
|
if (path.empty()) {
|
||||||
|
m_wallet->store();
|
||||||
|
} else {
|
||||||
|
m_wallet->store_to(path, m_password);
|
||||||
|
}
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
LOG_ERROR("Error storing wallet: " << e.what());
|
||||||
|
m_status = Status_Error;
|
||||||
|
m_errorString = e.what();
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_status == Status_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
void WalletImpl::clearStatus()
|
void WalletImpl::clearStatus()
|
||||||
{
|
{
|
||||||
m_status = Status_Ok;
|
m_status = Status_Ok;
|
||||||
|
@ -316,9 +334,9 @@ std::string WalletManagerImpl::errorString() const
|
||||||
///////////////////// WalletManagerFactory implementation //////////////////////
|
///////////////////// WalletManagerFactory implementation //////////////////////
|
||||||
WalletManager *WalletManagerFactory::getWalletManager()
|
WalletManager *WalletManagerFactory::getWalletManager()
|
||||||
{
|
{
|
||||||
// TODO: initialize logger here
|
|
||||||
epee::log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_0);
|
|
||||||
if (!g_walletManager) {
|
if (!g_walletManager) {
|
||||||
|
epee::log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_0);
|
||||||
g_walletManager = new WalletManagerImpl();
|
g_walletManager = new WalletManagerImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,7 @@ struct Wallet
|
||||||
virtual std::string errorString() const = 0;
|
virtual std::string errorString() const = 0;
|
||||||
virtual bool setPassword(const std::string &password) = 0;
|
virtual bool setPassword(const std::string &password) = 0;
|
||||||
virtual std::string address() const = 0;
|
virtual std::string address() const = 0;
|
||||||
|
virtual bool store(const std::string &path) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -210,7 +210,6 @@ namespace tools
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
typedef file_error_base<file_exists_message_index> file_exists;
|
typedef file_error_base<file_exists_message_index> file_exists;
|
||||||
typedef file_error_base<file_not_found_message_index> file_not_found;
|
typedef file_error_base<file_not_found_message_index> file_not_found;
|
||||||
typedef file_error_base<file_not_found_message_index> file_not_found;
|
|
||||||
typedef file_error_base<file_read_error_message_index> file_read_error;
|
typedef file_error_base<file_read_error_message_index> file_read_error;
|
||||||
typedef file_error_base<file_save_error_message_index> file_save_error;
|
typedef file_error_base<file_save_error_message_index> file_save_error;
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -47,6 +47,9 @@ struct WalletManagerTest : public testing::Test
|
||||||
Bitmonero::WalletManager * wmgr;
|
Bitmonero::WalletManager * wmgr;
|
||||||
|
|
||||||
const char * WALLET_NAME = "testwallet";
|
const char * WALLET_NAME = "testwallet";
|
||||||
|
const char * WALLET_NAME_COPY = "testwallet_copy";
|
||||||
|
const char * WALLET_NAME_WITH_DIR = "walletdir/testwallet_test";
|
||||||
|
const char * WALLET_NAME_WITH_DIR_NON_WRITABLE = "/var/walletdir/testwallet_test";
|
||||||
const char * WALLET_PASS = "password";
|
const char * WALLET_PASS = "password";
|
||||||
const char * WALLET_PASS2 = "password22";
|
const char * WALLET_PASS2 = "password22";
|
||||||
const char * WALLET_LANG = "English";
|
const char * WALLET_LANG = "English";
|
||||||
|
@ -56,6 +59,7 @@ struct WalletManagerTest : public testing::Test
|
||||||
std::cout << __FUNCTION__ << std::endl;
|
std::cout << __FUNCTION__ << std::endl;
|
||||||
wmgr = Bitmonero::WalletManagerFactory::getWalletManager();
|
wmgr = Bitmonero::WalletManagerFactory::getWalletManager();
|
||||||
deleteWallet(WALLET_NAME);
|
deleteWallet(WALLET_NAME);
|
||||||
|
deleteDir(boost::filesystem::path(WALLET_NAME_WITH_DIR).parent_path().string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,12 +72,18 @@ struct WalletManagerTest : public testing::Test
|
||||||
|
|
||||||
void deleteWallet(const std::string & walletname)
|
void deleteWallet(const std::string & walletname)
|
||||||
{
|
{
|
||||||
std::cout << "** deleting wallet " << std::endl;
|
std::cout << "** deleting wallet: " << walletname << std::endl;
|
||||||
boost::filesystem::remove(walletname);
|
boost::filesystem::remove(walletname);
|
||||||
boost::filesystem::remove(walletname + ".address.txt");
|
boost::filesystem::remove(walletname + ".address.txt");
|
||||||
boost::filesystem::remove(walletname + ".keys");
|
boost::filesystem::remove(walletname + ".keys");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void deleteDir(const std::string &path)
|
||||||
|
{
|
||||||
|
std::cout << "** removing dir recursively: " << path << std::endl;
|
||||||
|
boost::filesystem::remove_all(path);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -139,6 +149,59 @@ TEST_F(WalletManagerTest, WalletManagerRecoversWallet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_F(WalletManagerTest, WalletManagerStoresWallet1)
|
||||||
|
{
|
||||||
|
Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG);
|
||||||
|
std::string seed1 = wallet1->seed();
|
||||||
|
std::string address1 = wallet1->address();
|
||||||
|
|
||||||
|
ASSERT_TRUE(wallet1->store(""));
|
||||||
|
ASSERT_TRUE(wallet1->store(WALLET_NAME_COPY));
|
||||||
|
ASSERT_TRUE(wmgr->closeWallet(wallet1));
|
||||||
|
Bitmonero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME_COPY, WALLET_PASS);
|
||||||
|
ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok);
|
||||||
|
ASSERT_TRUE(wallet2->seed() == seed1);
|
||||||
|
ASSERT_TRUE(wallet2->address() == address1);
|
||||||
|
ASSERT_TRUE(wmgr->closeWallet(wallet2));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletManagerTest, WalletManagerStoresWallet2)
|
||||||
|
{
|
||||||
|
Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG);
|
||||||
|
std::string seed1 = wallet1->seed();
|
||||||
|
std::string address1 = wallet1->address();
|
||||||
|
|
||||||
|
ASSERT_TRUE(wallet1->store(WALLET_NAME_WITH_DIR));
|
||||||
|
ASSERT_TRUE(wmgr->closeWallet(wallet1));
|
||||||
|
|
||||||
|
wallet1 = wmgr->openWallet(WALLET_NAME_WITH_DIR, WALLET_PASS);
|
||||||
|
ASSERT_TRUE(wallet1->status() == Bitmonero::Wallet::Status_Ok);
|
||||||
|
ASSERT_TRUE(wallet1->seed() == seed1);
|
||||||
|
ASSERT_TRUE(wallet1->address() == address1);
|
||||||
|
ASSERT_TRUE(wmgr->closeWallet(wallet1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletManagerTest, WalletManagerStoresWallet3)
|
||||||
|
{
|
||||||
|
Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG);
|
||||||
|
std::string seed1 = wallet1->seed();
|
||||||
|
std::string address1 = wallet1->address();
|
||||||
|
|
||||||
|
ASSERT_FALSE(wallet1->store(WALLET_NAME_WITH_DIR_NON_WRITABLE));
|
||||||
|
ASSERT_TRUE(wmgr->closeWallet(wallet1));
|
||||||
|
|
||||||
|
wallet1 = wmgr->openWallet(WALLET_NAME_WITH_DIR_NON_WRITABLE, WALLET_PASS);
|
||||||
|
ASSERT_FALSE(wallet1->status() == Bitmonero::Wallet::Status_Ok);
|
||||||
|
|
||||||
|
ASSERT_FALSE(wmgr->closeWallet(wallet1));
|
||||||
|
|
||||||
|
wallet1 = wmgr->openWallet(WALLET_NAME, WALLET_PASS);
|
||||||
|
ASSERT_TRUE(wallet1->status() == Bitmonero::Wallet::Status_Ok);
|
||||||
|
ASSERT_TRUE(wallet1->seed() == seed1);
|
||||||
|
ASSERT_TRUE(wallet1->address() == address1);
|
||||||
|
ASSERT_TRUE(wmgr->closeWallet(wallet1));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
|
|
Loading…
Reference in New Issue