385 lines
15 KiB
C++
385 lines
15 KiB
C++
// Copyright (c) 2023-2024, 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 <cctype>
|
|
|
|
#include "file_io_utils.h"
|
|
#include "wallet/wallet2.h"
|
|
#include "common/util.h"
|
|
|
|
using namespace boost::filesystem;
|
|
using namespace epee::file_io_utils;
|
|
|
|
static constexpr const char WALLET_00fd416a_PRIMARY_ADDRESS[] =
|
|
"45p2SngJAPSJbqSiUvYfS3BfhEdxZmv8pDt25oW1LzxrZv9Uq6ARagiFViMGUE3gJk5VPWingCXVf1p2tyAy6SUeSHPhbve";
|
|
|
|
// https://github.com/monero-project/monero/blob/67d190ce7c33602b6a3b804f633ee1ddb7fbb4a1/src/wallet/wallet2.cpp#L156
|
|
static constexpr const char WALLET2_ASCII_OUTPUT_MAGIC[] = "MoneroAsciiDataV1";
|
|
|
|
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"));
|
|
|
|
tools::copy_file(source_wallet_file.string(), interm_wallet_file.string());
|
|
tools::copy_file(source_wallet_file.string() + ".keys", interm_wallet_file.string() + ".keys");
|
|
|
|
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"));
|
|
|
|
tools::copy_file(source_wallet_file.string(), interm_wallet_file.string());
|
|
tools::copy_file(source_wallet_file.string() + ".keys", interm_wallet_file.string() + ".keys");
|
|
|
|
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"));
|
|
|
|
tools::copy_file(source_wallet_file.string(), interm_wallet_file.string());
|
|
tools::copy_file(source_wallet_file.string() + ".keys", interm_wallet_file.string() + ".keys");
|
|
|
|
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);
|
|
}
|
|
|
|
TEST(wallet_storage, gen_ascii_format)
|
|
{
|
|
const path target_wallet_file = unit_test::data_dir / "wallet_gen_ascii_format";
|
|
|
|
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 password("https://safecurves.cr.yp.to/rigid.html");
|
|
|
|
std::string primary_address_1, primary_address_2;
|
|
{
|
|
tools::wallet2 w;
|
|
w.set_export_format(tools::wallet2::Ascii);
|
|
ASSERT_EQ(tools::wallet2::Ascii, w.export_format());
|
|
w.generate(target_wallet_file.string(), password);
|
|
primary_address_1 = w.get_address_as_str();
|
|
}
|
|
|
|
ASSERT_TRUE(is_file_exist(target_wallet_file.string()));
|
|
ASSERT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
|
|
|
|
// Assert that we store keys in ascii format
|
|
{
|
|
std::string key_file_contents;
|
|
ASSERT_TRUE(epee::file_io_utils::load_file_to_string(target_wallet_file.string() + ".keys", key_file_contents));
|
|
EXPECT_NE(std::string::npos, key_file_contents.find(WALLET2_ASCII_OUTPUT_MAGIC));
|
|
for (const char c : key_file_contents)
|
|
ASSERT_TRUE(std::isprint(c) || c == '\n' || c == '\r');
|
|
}
|
|
|
|
{
|
|
tools::wallet2 w;
|
|
w.set_export_format(tools::wallet2::Ascii);
|
|
ASSERT_EQ(tools::wallet2::Ascii, w.export_format());
|
|
w.load(target_wallet_file.string(), password);
|
|
primary_address_2 = w.get_address_as_str();
|
|
}
|
|
|
|
EXPECT_EQ(primary_address_1, primary_address_2);
|
|
}
|
|
|
|
TEST(wallet_storage, change_export_format)
|
|
{
|
|
const path target_wallet_file = unit_test::data_dir / "wallet_change_export_format";
|
|
|
|
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 password("https://safecurves.cr.yp.to/rigid.html");
|
|
|
|
std::string primary_address_1, primary_address_2;
|
|
{
|
|
tools::wallet2 w;
|
|
ASSERT_EQ(tools::wallet2::Binary, w.export_format());
|
|
w.generate(target_wallet_file.string(), password);
|
|
primary_address_1 = w.get_address_as_str();
|
|
w.store();
|
|
|
|
// Assert that we initially store keys in binary format
|
|
{
|
|
std::string key_file_contents;
|
|
ASSERT_TRUE(epee::file_io_utils::load_file_to_string(target_wallet_file.string() + ".keys", key_file_contents));
|
|
EXPECT_EQ(std::string::npos, key_file_contents.find(WALLET2_ASCII_OUTPUT_MAGIC));
|
|
bool only_printable = true;
|
|
for (const char c : key_file_contents)
|
|
{
|
|
if (!std::isprint(c) && c != '\n' && c != '\r')
|
|
{
|
|
only_printable = false;
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_FALSE(only_printable);
|
|
}
|
|
|
|
// switch formats and store
|
|
w.set_export_format(tools::wallet2::Ascii);
|
|
ASSERT_EQ(tools::wallet2::Ascii, w.export_format());
|
|
w.store_to("", password, /*force_rewrite_keys=*/ true);
|
|
}
|
|
|
|
ASSERT_TRUE(is_file_exist(target_wallet_file.string()));
|
|
ASSERT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
|
|
|
|
// Assert that we store keys in ascii format
|
|
{
|
|
std::string key_file_contents;
|
|
ASSERT_TRUE(epee::file_io_utils::load_file_to_string(target_wallet_file.string() + ".keys", key_file_contents));
|
|
EXPECT_NE(std::string::npos, key_file_contents.find(WALLET2_ASCII_OUTPUT_MAGIC));
|
|
for (const char c : key_file_contents)
|
|
ASSERT_TRUE(std::isprint(c) || c == '\n' || c == '\r');
|
|
}
|
|
|
|
{
|
|
tools::wallet2 w;
|
|
w.set_export_format(tools::wallet2::Ascii);
|
|
ASSERT_EQ(tools::wallet2::Ascii, w.export_format());
|
|
w.load(target_wallet_file.string(), password);
|
|
primary_address_2 = w.get_address_as_str();
|
|
}
|
|
|
|
EXPECT_EQ(primary_address_1, primary_address_2);
|
|
}
|