wallet2: fix `store_to()` and `change_password()`
Resolves #8932 and: 2. Not storing cache when new path is different from old in `store_to()` and 3. Detecting same path when new path contains entire string of old path in `store_to()` and 4. Changing your password / decrypting your keys (in this method or others) and providing a bad original password and getting no error and 5. Changing your password and storing to a new file
This commit is contained in:
parent
8123d945f8
commit
1bea8ef42a
|
@ -1001,6 +1001,24 @@ uint64_t num_priv_multisig_keys_post_setup(uint64_t threshold, uint64_t total)
|
||||||
return n_multisig_keys;
|
return n_multisig_keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Derives the chacha key to encrypt wallet cache files given the chacha key to encrypt the wallet keys files
|
||||||
|
*
|
||||||
|
* @param keys_data_key the chacha key that encrypts wallet keys files
|
||||||
|
* @return crypto::chacha_key the chacha key that encrypts the wallet cache files
|
||||||
|
*/
|
||||||
|
crypto::chacha_key derive_cache_key(const crypto::chacha_key& keys_data_key)
|
||||||
|
{
|
||||||
|
static_assert(HASH_SIZE == sizeof(crypto::chacha_key), "Mismatched sizes of hash and chacha key");
|
||||||
|
|
||||||
|
crypto::chacha_key cache_key;
|
||||||
|
epee::mlocked<tools::scrubbed_arr<char, HASH_SIZE+1>> cache_key_data;
|
||||||
|
memcpy(cache_key_data.data(), &keys_data_key, HASH_SIZE);
|
||||||
|
cache_key_data[HASH_SIZE] = config::HASH_KEY_WALLET_CACHE;
|
||||||
|
cn_fast_hash(cache_key_data.data(), HASH_SIZE+1, (crypto::hash&) cache_key);
|
||||||
|
|
||||||
|
return cache_key;
|
||||||
|
}
|
||||||
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
||||||
} //namespace
|
} //namespace
|
||||||
|
|
||||||
|
@ -4348,6 +4366,10 @@ boost::optional<wallet2::keys_file_data> wallet2::get_keys_file_data(const epee:
|
||||||
crypto::chacha_key key;
|
crypto::chacha_key key;
|
||||||
crypto::generate_chacha_key(password.data(), password.size(), key, m_kdf_rounds);
|
crypto::generate_chacha_key(password.data(), password.size(), key, m_kdf_rounds);
|
||||||
|
|
||||||
|
// We use m_cache_key as a deterministic test to see if given key corresponds to original password
|
||||||
|
const crypto::chacha_key cache_key = derive_cache_key(key);
|
||||||
|
THROW_WALLET_EXCEPTION_IF(cache_key != m_cache_key, error::invalid_password);
|
||||||
|
|
||||||
if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only)
|
if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only)
|
||||||
{
|
{
|
||||||
account.encrypt_viewkey(key);
|
account.encrypt_viewkey(key);
|
||||||
|
@ -4575,11 +4597,8 @@ void wallet2::setup_keys(const epee::wipeable_string &password)
|
||||||
m_account.decrypt_viewkey(key);
|
m_account.decrypt_viewkey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert(HASH_SIZE == sizeof(crypto::chacha_key), "Mismatched sizes of hash and chacha key");
|
m_cache_key = derive_cache_key(key);
|
||||||
epee::mlocked<tools::scrubbed_arr<char, HASH_SIZE+1>> cache_key_data;
|
|
||||||
memcpy(cache_key_data.data(), &key, HASH_SIZE);
|
|
||||||
cache_key_data[HASH_SIZE] = config::HASH_KEY_WALLET_CACHE;
|
|
||||||
cn_fast_hash(cache_key_data.data(), HASH_SIZE+1, (crypto::hash&)m_cache_key);
|
|
||||||
get_ringdb_key();
|
get_ringdb_key();
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
@ -4588,9 +4607,8 @@ void wallet2::change_password(const std::string &filename, const epee::wipeable_
|
||||||
if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only)
|
if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only)
|
||||||
decrypt_keys(original_password);
|
decrypt_keys(original_password);
|
||||||
setup_keys(new_password);
|
setup_keys(new_password);
|
||||||
rewrite(filename, new_password);
|
|
||||||
if (!filename.empty())
|
if (!filename.empty())
|
||||||
store();
|
store_to(filename, new_password, true); // force rewrite keys file to possible new location
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
/*!
|
/*!
|
||||||
|
@ -5083,6 +5101,10 @@ void wallet2::encrypt_keys(const crypto::chacha_key &key)
|
||||||
|
|
||||||
void wallet2::decrypt_keys(const crypto::chacha_key &key)
|
void wallet2::decrypt_keys(const crypto::chacha_key &key)
|
||||||
{
|
{
|
||||||
|
// We use m_cache_key as a deterministic test to see if given key corresponds to original password
|
||||||
|
const crypto::chacha_key cache_key = derive_cache_key(key);
|
||||||
|
THROW_WALLET_EXCEPTION_IF(cache_key != m_cache_key, error::invalid_password);
|
||||||
|
|
||||||
m_account.encrypt_viewkey(key);
|
m_account.encrypt_viewkey(key);
|
||||||
m_account.decrypt_keys(key);
|
m_account.decrypt_keys(key);
|
||||||
}
|
}
|
||||||
|
@ -6230,22 +6252,32 @@ void wallet2::store()
|
||||||
store_to("", epee::wipeable_string());
|
store_to("", epee::wipeable_string());
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
void wallet2::store_to(const std::string &path, const epee::wipeable_string &password)
|
void wallet2::store_to(const std::string &path, const epee::wipeable_string &password, bool force_rewrite_keys)
|
||||||
{
|
{
|
||||||
trim_hashchain();
|
trim_hashchain();
|
||||||
|
|
||||||
|
const bool had_old_wallet_files = !m_wallet_file.empty();
|
||||||
|
THROW_WALLET_EXCEPTION_IF(!had_old_wallet_files && path.empty(), error::wallet_internal_error,
|
||||||
|
"Cannot resave wallet to current file since wallet was not loaded from file to begin with");
|
||||||
|
|
||||||
// if file is the same, we do:
|
// if file is the same, we do:
|
||||||
// 1. save wallet to the *.new file
|
// 1. overwrite the keys file iff force_rewrite_keys is specified
|
||||||
// 2. remove old wallet file
|
// 2. save cache to the *.new file
|
||||||
// 3. rename *.new to wallet_name
|
// 3. rename *.new to wallet_name, replacing old cache file
|
||||||
|
// else we do:
|
||||||
|
// 1. prepare new file names with "path" variable
|
||||||
|
// 2. store new keys files
|
||||||
|
// 3. remove old keys file
|
||||||
|
// 4. store new cache file
|
||||||
|
// 5. remove old cache file
|
||||||
|
|
||||||
// handle if we want just store wallet state to current files (ex store() replacement);
|
// handle if we want just store wallet state to current files (ex store() replacement);
|
||||||
bool same_file = true;
|
bool same_file = had_old_wallet_files && path.empty();
|
||||||
if (!path.empty())
|
if (had_old_wallet_files && !path.empty())
|
||||||
{
|
{
|
||||||
std::string canonical_path = boost::filesystem::canonical(m_wallet_file).string();
|
const std::string canonical_old_path = boost::filesystem::canonical(m_wallet_file).string();
|
||||||
size_t pos = canonical_path.find(path);
|
const std::string canonical_new_path = boost::filesystem::weakly_canonical(path).string();
|
||||||
same_file = pos != std::string::npos;
|
same_file = canonical_old_path == canonical_new_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -6266,7 +6298,7 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
|
||||||
}
|
}
|
||||||
|
|
||||||
// get wallet cache data
|
// get wallet cache data
|
||||||
boost::optional<wallet2::cache_file_data> cache_file_data = get_cache_file_data(password);
|
boost::optional<wallet2::cache_file_data> cache_file_data = get_cache_file_data();
|
||||||
THROW_WALLET_EXCEPTION_IF(cache_file_data == boost::none, error::wallet_internal_error, "failed to generate wallet cache data");
|
THROW_WALLET_EXCEPTION_IF(cache_file_data == boost::none, error::wallet_internal_error, "failed to generate wallet cache data");
|
||||||
|
|
||||||
const std::string new_file = same_file ? m_wallet_file + ".new" : path;
|
const std::string new_file = same_file ? m_wallet_file + ".new" : path;
|
||||||
|
@ -6275,12 +6307,20 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
|
||||||
const std::string old_address_file = m_wallet_file + ".address.txt";
|
const std::string old_address_file = m_wallet_file + ".address.txt";
|
||||||
const std::string old_mms_file = m_mms_file;
|
const std::string old_mms_file = m_mms_file;
|
||||||
|
|
||||||
// save keys to the new file
|
if (!same_file)
|
||||||
// if we here, main wallet file is saved and we only need to save keys and address files
|
{
|
||||||
if (!same_file) {
|
|
||||||
prepare_file_names(path);
|
prepare_file_names(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!same_file || force_rewrite_keys)
|
||||||
|
{
|
||||||
bool r = store_keys(m_keys_file, password, false);
|
bool r = store_keys(m_keys_file, password, false);
|
||||||
THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file);
|
THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!same_file && had_old_wallet_files)
|
||||||
|
{
|
||||||
|
bool r = false;
|
||||||
if (boost::filesystem::exists(old_address_file))
|
if (boost::filesystem::exists(old_address_file))
|
||||||
{
|
{
|
||||||
// save address to the new file
|
// save address to the new file
|
||||||
|
@ -6293,11 +6333,6 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
|
||||||
LOG_ERROR("error removing file: " << old_address_file);
|
LOG_ERROR("error removing file: " << old_address_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// remove old wallet file
|
|
||||||
r = boost::filesystem::remove(old_file);
|
|
||||||
if (!r) {
|
|
||||||
LOG_ERROR("error removing file: " << old_file);
|
|
||||||
}
|
|
||||||
// remove old keys file
|
// remove old keys file
|
||||||
r = boost::filesystem::remove(old_keys_file);
|
r = boost::filesystem::remove(old_keys_file);
|
||||||
if (!r) {
|
if (!r) {
|
||||||
|
@ -6311,8 +6346,9 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
|
||||||
LOG_ERROR("error removing file: " << old_mms_file);
|
LOG_ERROR("error removing file: " << old_mms_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
// save to new file
|
|
||||||
|
// Save cache to new file. If storing to the same file, the temp path has the ".new" extension
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
// On Windows avoid using std::ofstream which does not work with UTF-8 filenames
|
// On Windows avoid using std::ofstream which does not work with UTF-8 filenames
|
||||||
// The price to pay is temporary higher memory consumption for string stream + binary archive
|
// The price to pay is temporary higher memory consumption for string stream + binary archive
|
||||||
|
@ -6332,10 +6368,20 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
|
||||||
THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file);
|
THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (same_file)
|
||||||
|
{
|
||||||
// here we have "*.new" file, we need to rename it to be without ".new"
|
// here we have "*.new" file, we need to rename it to be without ".new"
|
||||||
std::error_code e = tools::replace_file(new_file, m_wallet_file);
|
std::error_code e = tools::replace_file(new_file, m_wallet_file);
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
else if (!same_file && had_old_wallet_files)
|
||||||
|
{
|
||||||
|
// remove old wallet file
|
||||||
|
bool r = boost::filesystem::remove(old_file);
|
||||||
|
if (!r) {
|
||||||
|
LOG_ERROR("error removing file: " << old_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_message_store.get_active())
|
if (m_message_store.get_active())
|
||||||
{
|
{
|
||||||
|
@ -6345,7 +6391,7 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
boost::optional<wallet2::cache_file_data> wallet2::get_cache_file_data(const epee::wipeable_string &passwords)
|
boost::optional<wallet2::cache_file_data> wallet2::get_cache_file_data()
|
||||||
{
|
{
|
||||||
trim_hashchain();
|
trim_hashchain();
|
||||||
try
|
try
|
||||||
|
|
|
@ -933,22 +933,32 @@ private:
|
||||||
/*!
|
/*!
|
||||||
* \brief store_to Stores wallet to another file(s), deleting old ones
|
* \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 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?)
|
* \param password Password that currently locks the wallet
|
||||||
|
* \param force_rewrite_keys if true, always rewrite keys file
|
||||||
|
*
|
||||||
|
* Leave both "path" and "password" blank to restore the cache file to the current position in the disk
|
||||||
|
* (which is the same as calling `store()`). If you want to store the wallet with a new password,
|
||||||
|
* use the method `change_password()`.
|
||||||
|
*
|
||||||
|
* Normally the keys file is not overwritten when storing, except when force_rewrite_keys is true
|
||||||
|
* or when `path` is a new wallet file.
|
||||||
|
*
|
||||||
|
* \throw error::invalid_password If storing keys file and old password is incorrect
|
||||||
*/
|
*/
|
||||||
void store_to(const std::string &path, const epee::wipeable_string &password);
|
void store_to(const std::string &path, const epee::wipeable_string &password, bool force_rewrite_keys = false);
|
||||||
/*!
|
/*!
|
||||||
* \brief get_keys_file_data Get wallet keys data which can be stored to a wallet file.
|
* \brief get_keys_file_data Get wallet keys data which can be stored to a wallet file.
|
||||||
* \param password Password of the encrypted wallet buffer (TODO: probably better save the password in the wallet object?)
|
* \param password Password that currently locks the wallet
|
||||||
* \param watch_only true to include only view key, false to include both spend and view keys
|
* \param watch_only true to include only view key, false to include both spend and view keys
|
||||||
* \return Encrypted wallet keys data which can be stored to a wallet file
|
* \return Encrypted wallet keys data which can be stored to a wallet file
|
||||||
|
* \throw error::invalid_password if password does not match current wallet
|
||||||
*/
|
*/
|
||||||
boost::optional<wallet2::keys_file_data> get_keys_file_data(const epee::wipeable_string& password, bool watch_only);
|
boost::optional<wallet2::keys_file_data> get_keys_file_data(const epee::wipeable_string& password, bool watch_only);
|
||||||
/*!
|
/*!
|
||||||
* \brief get_cache_file_data Get wallet cache data which can be stored to a wallet file.
|
* \brief get_cache_file_data Get wallet cache data which can be stored to a wallet file.
|
||||||
* \param password Password to protect the wallet cache data (TODO: probably better save the password in the wallet object?)
|
* \return Encrypted wallet cache data which can be stored to a wallet file (using current password)
|
||||||
* \return Encrypted wallet cache data which can be stored to a wallet file
|
|
||||||
*/
|
*/
|
||||||
boost::optional<wallet2::cache_file_data> get_cache_file_data(const epee::wipeable_string& password);
|
boost::optional<wallet2::cache_file_data> get_cache_file_data();
|
||||||
|
|
||||||
std::string path() const;
|
std::string path() const;
|
||||||
|
|
||||||
|
|
|
@ -72,14 +72,8 @@ else ()
|
||||||
include_directories(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/gtest/include")
|
include_directories(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/gtest/include")
|
||||||
endif (GTest_FOUND)
|
endif (GTest_FOUND)
|
||||||
|
|
||||||
file(COPY
|
message(STATUS "Copying test data directory...")
|
||||||
data/wallet_9svHk1.keys
|
file(COPY data DESTINATION .) # Copy data directory from source root to build root
|
||||||
data/wallet_9svHk1
|
|
||||||
data/outputs
|
|
||||||
data/unsigned_monero_tx
|
|
||||||
data/signed_monero_tx
|
|
||||||
data/sha256sum
|
|
||||||
DESTINATION data)
|
|
||||||
|
|
||||||
if (CMAKE_BUILD_TYPE STREQUAL "fuzz" OR OSSFUZZ)
|
if (CMAKE_BUILD_TYPE STREQUAL "fuzz" OR OSSFUZZ)
|
||||||
add_subdirectory(fuzz)
|
add_subdirectory(fuzz)
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -98,6 +98,7 @@ set(unit_tests_sources
|
||||||
output_selection.cpp
|
output_selection.cpp
|
||||||
vercmp.cpp
|
vercmp.cpp
|
||||||
ringdb.cpp
|
ringdb.cpp
|
||||||
|
wallet_storage.cpp
|
||||||
wipeable_string.cpp
|
wipeable_string.cpp
|
||||||
is_hdd.cpp
|
is_hdd.cpp
|
||||||
aligned.cpp
|
aligned.cpp
|
||||||
|
|
|
@ -0,0 +1,266 @@
|
||||||
|
// Copyright (c) 2023, The Monero Project
|
||||||
|
//
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without modification, are
|
||||||
|
// permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
// conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
// of conditions and the following disclaimer in the documentation and/or other
|
||||||
|
// materials provided with the distribution.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without specific
|
||||||
|
// prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||||
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||||
|
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||||
|
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#include "unit_tests_utils.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
#include "file_io_utils.h"
|
||||||
|
#include "wallet/wallet2.h"
|
||||||
|
|
||||||
|
using namespace boost::filesystem;
|
||||||
|
using namespace epee::file_io_utils;
|
||||||
|
|
||||||
|
static constexpr const char WALLET_00fd416a_PRIMARY_ADDRESS[] =
|
||||||
|
"45p2SngJAPSJbqSiUvYfS3BfhEdxZmv8pDt25oW1LzxrZv9Uq6ARagiFViMGUE3gJk5VPWingCXVf1p2tyAy6SUeSHPhbve";
|
||||||
|
|
||||||
|
TEST(wallet_storage, store_to_file2file)
|
||||||
|
{
|
||||||
|
const path source_wallet_file = unit_test::data_dir / "wallet_00fd416a";
|
||||||
|
const path interm_wallet_file = unit_test::data_dir / "wallet_00fd416a_copy_file2file";
|
||||||
|
const path target_wallet_file = unit_test::data_dir / "wallet_00fd416a_new_file2file";
|
||||||
|
|
||||||
|
ASSERT_TRUE(is_file_exist(source_wallet_file.string()));
|
||||||
|
ASSERT_TRUE(is_file_exist(source_wallet_file.string() + ".keys"));
|
||||||
|
|
||||||
|
copy_file(source_wallet_file, interm_wallet_file, copy_option::overwrite_if_exists);
|
||||||
|
copy_file(source_wallet_file.string() + ".keys", interm_wallet_file.string() + ".keys", copy_option::overwrite_if_exists);
|
||||||
|
|
||||||
|
ASSERT_TRUE(is_file_exist(interm_wallet_file.string()));
|
||||||
|
ASSERT_TRUE(is_file_exist(interm_wallet_file.string() + ".keys"));
|
||||||
|
|
||||||
|
if (is_file_exist(target_wallet_file.string()))
|
||||||
|
remove(target_wallet_file);
|
||||||
|
if (is_file_exist(target_wallet_file.string() + ".keys"))
|
||||||
|
remove(target_wallet_file.string() + ".keys");
|
||||||
|
ASSERT_FALSE(is_file_exist(target_wallet_file.string()));
|
||||||
|
ASSERT_FALSE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||||
|
|
||||||
|
epee::wipeable_string password("beepbeep");
|
||||||
|
|
||||||
|
const auto files_are_expected = [&]()
|
||||||
|
{
|
||||||
|
EXPECT_FALSE(is_file_exist(interm_wallet_file.string()));
|
||||||
|
EXPECT_FALSE(is_file_exist(interm_wallet_file.string() + ".keys"));
|
||||||
|
EXPECT_TRUE(is_file_exist(target_wallet_file.string()));
|
||||||
|
EXPECT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
tools::wallet2 w;
|
||||||
|
w.load(interm_wallet_file.string(), password);
|
||||||
|
const std::string primary_address = w.get_address_as_str();
|
||||||
|
EXPECT_EQ(WALLET_00fd416a_PRIMARY_ADDRESS, primary_address);
|
||||||
|
w.store_to(target_wallet_file.string(), password);
|
||||||
|
files_are_expected();
|
||||||
|
}
|
||||||
|
|
||||||
|
files_are_expected();
|
||||||
|
|
||||||
|
{
|
||||||
|
tools::wallet2 w;
|
||||||
|
w.load(target_wallet_file.string(), password);
|
||||||
|
const std::string primary_address = w.get_address_as_str();
|
||||||
|
EXPECT_EQ(WALLET_00fd416a_PRIMARY_ADDRESS, primary_address);
|
||||||
|
w.store_to("", "");
|
||||||
|
files_are_expected();
|
||||||
|
}
|
||||||
|
|
||||||
|
files_are_expected();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(wallet_storage, store_to_mem2file)
|
||||||
|
{
|
||||||
|
const path target_wallet_file = unit_test::data_dir / "wallet_mem2file";
|
||||||
|
|
||||||
|
if (is_file_exist(target_wallet_file.string()))
|
||||||
|
remove(target_wallet_file);
|
||||||
|
if (is_file_exist(target_wallet_file.string() + ".keys"))
|
||||||
|
remove(target_wallet_file.string() + ".keys");
|
||||||
|
ASSERT_FALSE(is_file_exist(target_wallet_file.string()));
|
||||||
|
ASSERT_FALSE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||||
|
|
||||||
|
epee::wipeable_string password("beepbeep2");
|
||||||
|
|
||||||
|
{
|
||||||
|
tools::wallet2 w;
|
||||||
|
w.generate("", password);
|
||||||
|
w.store_to(target_wallet_file.string(), password);
|
||||||
|
|
||||||
|
EXPECT_TRUE(is_file_exist(target_wallet_file.string()));
|
||||||
|
EXPECT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_TRUE(is_file_exist(target_wallet_file.string()));
|
||||||
|
EXPECT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||||
|
|
||||||
|
{
|
||||||
|
tools::wallet2 w;
|
||||||
|
w.load(target_wallet_file.string(), password);
|
||||||
|
|
||||||
|
EXPECT_TRUE(is_file_exist(target_wallet_file.string()));
|
||||||
|
EXPECT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_TRUE(is_file_exist(target_wallet_file.string()));
|
||||||
|
EXPECT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(wallet_storage, change_password_same_file)
|
||||||
|
{
|
||||||
|
const path source_wallet_file = unit_test::data_dir / "wallet_00fd416a";
|
||||||
|
const path interm_wallet_file = unit_test::data_dir / "wallet_00fd416a_copy_change_password_same";
|
||||||
|
|
||||||
|
ASSERT_TRUE(is_file_exist(source_wallet_file.string()));
|
||||||
|
ASSERT_TRUE(is_file_exist(source_wallet_file.string() + ".keys"));
|
||||||
|
|
||||||
|
copy_file(source_wallet_file, interm_wallet_file, copy_option::overwrite_if_exists);
|
||||||
|
copy_file(source_wallet_file.string() + ".keys", interm_wallet_file.string() + ".keys", copy_option::overwrite_if_exists);
|
||||||
|
|
||||||
|
ASSERT_TRUE(is_file_exist(interm_wallet_file.string()));
|
||||||
|
ASSERT_TRUE(is_file_exist(interm_wallet_file.string() + ".keys"));
|
||||||
|
|
||||||
|
epee::wipeable_string old_password("beepbeep");
|
||||||
|
epee::wipeable_string new_password("meepmeep");
|
||||||
|
|
||||||
|
{
|
||||||
|
tools::wallet2 w;
|
||||||
|
w.load(interm_wallet_file.string(), old_password);
|
||||||
|
const std::string primary_address = w.get_address_as_str();
|
||||||
|
EXPECT_EQ(WALLET_00fd416a_PRIMARY_ADDRESS, primary_address);
|
||||||
|
w.change_password(w.get_wallet_file(), old_password, new_password);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tools::wallet2 w;
|
||||||
|
w.load(interm_wallet_file.string(), new_password);
|
||||||
|
const std::string primary_address = w.get_address_as_str();
|
||||||
|
EXPECT_EQ(WALLET_00fd416a_PRIMARY_ADDRESS, primary_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tools::wallet2 w;
|
||||||
|
EXPECT_THROW(w.load(interm_wallet_file.string(), old_password), tools::error::invalid_password);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(wallet_storage, change_password_different_file)
|
||||||
|
{
|
||||||
|
const path source_wallet_file = unit_test::data_dir / "wallet_00fd416a";
|
||||||
|
const path interm_wallet_file = unit_test::data_dir / "wallet_00fd416a_copy_change_password_diff";
|
||||||
|
const path target_wallet_file = unit_test::data_dir / "wallet_00fd416a_new_change_password_diff";
|
||||||
|
|
||||||
|
ASSERT_TRUE(is_file_exist(source_wallet_file.string()));
|
||||||
|
ASSERT_TRUE(is_file_exist(source_wallet_file.string() + ".keys"));
|
||||||
|
|
||||||
|
copy_file(source_wallet_file, interm_wallet_file, copy_option::overwrite_if_exists);
|
||||||
|
copy_file(source_wallet_file.string() + ".keys", interm_wallet_file.string() + ".keys", copy_option::overwrite_if_exists);
|
||||||
|
|
||||||
|
ASSERT_TRUE(is_file_exist(interm_wallet_file.string()));
|
||||||
|
ASSERT_TRUE(is_file_exist(interm_wallet_file.string() + ".keys"));
|
||||||
|
|
||||||
|
if (is_file_exist(target_wallet_file.string()))
|
||||||
|
remove(target_wallet_file);
|
||||||
|
if (is_file_exist(target_wallet_file.string() + ".keys"))
|
||||||
|
remove(target_wallet_file.string() + ".keys");
|
||||||
|
ASSERT_FALSE(is_file_exist(target_wallet_file.string()));
|
||||||
|
ASSERT_FALSE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||||
|
|
||||||
|
epee::wipeable_string old_password("beepbeep");
|
||||||
|
epee::wipeable_string new_password("meepmeep");
|
||||||
|
|
||||||
|
{
|
||||||
|
tools::wallet2 w;
|
||||||
|
w.load(interm_wallet_file.string(), old_password);
|
||||||
|
const std::string primary_address = w.get_address_as_str();
|
||||||
|
EXPECT_EQ(WALLET_00fd416a_PRIMARY_ADDRESS, primary_address);
|
||||||
|
w.change_password(target_wallet_file.string(), old_password, new_password);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_FALSE(is_file_exist(interm_wallet_file.string()));
|
||||||
|
EXPECT_FALSE(is_file_exist(interm_wallet_file.string() + ".keys"));
|
||||||
|
EXPECT_TRUE(is_file_exist(target_wallet_file.string()));
|
||||||
|
EXPECT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||||
|
|
||||||
|
{
|
||||||
|
tools::wallet2 w;
|
||||||
|
w.load(target_wallet_file.string(), new_password);
|
||||||
|
const std::string primary_address = w.get_address_as_str();
|
||||||
|
EXPECT_EQ(WALLET_00fd416a_PRIMARY_ADDRESS, primary_address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(wallet_storage, change_password_in_memory)
|
||||||
|
{
|
||||||
|
const epee::wipeable_string password1("monero");
|
||||||
|
const epee::wipeable_string password2("means money");
|
||||||
|
const epee::wipeable_string password_wrong("is traceable");
|
||||||
|
|
||||||
|
tools::wallet2 w;
|
||||||
|
w.generate("", password1);
|
||||||
|
const std::string primary_address_1 = w.get_address_as_str();
|
||||||
|
w.change_password("", password1, password2);
|
||||||
|
const std::string primary_address_2 = w.get_address_as_str();
|
||||||
|
EXPECT_EQ(primary_address_1, primary_address_2);
|
||||||
|
|
||||||
|
EXPECT_THROW(w.change_password("", password_wrong, password1), tools::error::invalid_password);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(wallet_storage, change_password_mem2file)
|
||||||
|
{
|
||||||
|
const path target_wallet_file = unit_test::data_dir / "wallet_change_password_mem2file";
|
||||||
|
|
||||||
|
if (is_file_exist(target_wallet_file.string()))
|
||||||
|
remove(target_wallet_file);
|
||||||
|
if (is_file_exist(target_wallet_file.string() + ".keys"))
|
||||||
|
remove(target_wallet_file.string() + ".keys");
|
||||||
|
ASSERT_FALSE(is_file_exist(target_wallet_file.string()));
|
||||||
|
ASSERT_FALSE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||||
|
|
||||||
|
const epee::wipeable_string password1("https://safecurves.cr.yp.to/rigid.html");
|
||||||
|
const epee::wipeable_string password2(
|
||||||
|
"https://csrc.nist.gov/csrc/media/projects/crypto-standards-development-process/documents/dualec_in_x982_and_sp800-90.pdf");
|
||||||
|
|
||||||
|
std::string primary_address_1, primary_address_2;
|
||||||
|
{
|
||||||
|
tools::wallet2 w;
|
||||||
|
w.generate("", password1);
|
||||||
|
primary_address_1 = w.get_address_as_str();
|
||||||
|
w.change_password(target_wallet_file.string(), password1, password2);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_TRUE(is_file_exist(target_wallet_file.string()));
|
||||||
|
EXPECT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||||
|
|
||||||
|
{
|
||||||
|
tools::wallet2 w;
|
||||||
|
w.load(target_wallet_file.string(), password2);
|
||||||
|
primary_address_2 = w.get_address_as_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(primary_address_1, primary_address_2);
|
||||||
|
}
|
Loading…
Reference in New Issue