aboutsummaryrefslogtreecommitdiff
path: root/src/simplewallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/simplewallet')
-rw-r--r--src/simplewallet/simplewallet.cpp516
-rw-r--r--src/simplewallet/simplewallet.h17
2 files changed, 382 insertions, 151 deletions
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 0d48dba34..e0dbe96e7 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -106,6 +106,12 @@ typedef cryptonote::simple_wallet sw;
m_auto_refresh_enabled.store(auto_refresh_enabled, std::memory_order_relaxed); \
})
+#define SCOPED_WALLET_UNLOCK() \
+ LOCK_IDLE_SCOPE(); \
+ boost::optional<tools::password_container> pwd_container = boost::none; \
+ if (m_wallet->ask_password() && !m_wallet->watch_only() && !(pwd_container = get_and_verify_password())) { return true; } \
+ tools::wallet_keys_unlocker unlocker(*m_wallet, pwd_container);
+
enum TransferType {
TransferOriginal,
TransferNew,
@@ -152,12 +158,31 @@ namespace
//
// Note also that input for passwords is NOT translated, to remain compatible with any
// passwords containing special characters that predate this switch to UTF-8 support.
- static std::string cp850_to_utf8(const std::string &cp850_str)
+ template<typename T>
+ static T cp850_to_utf8(const T &cp850_str)
{
boost::locale::generator gen;
gen.locale_cache_enabled(true);
std::locale loc = gen("en_US.CP850");
- return boost::locale::conv::to_utf<char>(cp850_str, loc);
+ const boost::locale::conv::method_type how = boost::locale::conv::default_method;
+ T result;
+ const char *begin = cp850_str.data();
+ const char *end = begin + cp850_str.size();
+ result.reserve(end-begin);
+ typedef std::back_insert_iterator<T> inserter_type;
+ inserter_type inserter(result);
+ boost::locale::utf::code_point c;
+ while(begin!=end) {
+ c=boost::locale::utf::utf_traits<char>::template decode<char const *>(begin,end);
+ if(c==boost::locale::utf::illegal || c==boost::locale::utf::incomplete) {
+ if(how==boost::locale::conv::stop)
+ throw boost::locale::conv::conversion_error();
+ }
+ else {
+ boost::locale::utf::utf_traits<char>::template encode<inserter_type>(c,inserter);
+ }
+ }
+ return result;
}
#endif
@@ -177,6 +202,28 @@ namespace
return epee::string_tools::trim(buf);
}
+ epee::wipeable_string input_secure_line(const std::string& prompt)
+ {
+#ifdef HAVE_READLINE
+ rdln::suspend_readline pause_readline;
+#endif
+ auto pwd_container = tools::password_container::prompt(false, prompt.c_str(), false);
+ if (!pwd_container)
+ {
+ MERROR("Failed to read secure line");
+ return "";
+ }
+
+ epee::wipeable_string buf = pwd_container->password();
+
+#ifdef WIN32
+ buf = cp850_to_utf8(buf);
+#endif
+
+ buf.trim();
+ return buf;
+ }
+
boost::optional<tools::password_container> password_prompter(const char *prompt, bool verify)
{
#ifdef HAVE_READLINE
@@ -512,6 +559,18 @@ namespace
}
return true;
}
+
+ void print_secret_key(const crypto::secret_key &k)
+ {
+ static constexpr const char hex[] = u8"0123456789abcdef";
+ const uint8_t *ptr = (const uint8_t*)k.data;
+ for (size_t i = 0, sz = sizeof(k); i < sz; ++i)
+ {
+ putchar(hex[*ptr >> 4]);
+ putchar(hex[*ptr & 15]);
+ ++ptr;
+ }
+ }
}
bool parse_priority(const std::string& arg, uint32_t& priority)
@@ -561,12 +620,15 @@ std::string simple_wallet::get_command_usage(const std::vector<std::string> &arg
bool simple_wallet::viewkey(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
- if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
+ SCOPED_WALLET_UNLOCK();
// don't log
+ PAUSE_READLINE();
if (m_wallet->key_on_device()) {
std::cout << "secret: On device. Not available" << std::endl;
} else {
- std::cout << "secret: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_view_secret_key) << std::endl;
+ printf("secret: ");
+ print_secret_key(m_wallet->get_account().get_keys().m_view_secret_key);
+ putchar('\n');
}
std::cout << "public: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_account_address.m_view_public_key) << std::endl;
@@ -580,12 +642,15 @@ bool simple_wallet::spendkey(const std::vector<std::string> &args/* = std::vecto
fail_msg_writer() << tr("wallet is watch-only and has no spend key");
return true;
}
- if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
+ SCOPED_WALLET_UNLOCK();
// don't log
+ PAUSE_READLINE();
if (m_wallet->key_on_device()) {
std::cout << "secret: On device. Not available" << std::endl;
} else {
- std::cout << "secret: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_spend_secret_key) << std::endl;
+ printf("secret: ");
+ print_secret_key(m_wallet->get_account().get_keys().m_spend_secret_key);
+ putchar('\n');
}
std::cout << "public: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_account_address.m_spend_public_key) << std::endl;
@@ -595,7 +660,7 @@ bool simple_wallet::spendkey(const std::vector<std::string> &args/* = std::vecto
bool simple_wallet::print_seed(bool encrypted)
{
bool success = false;
- std::string seed;
+ epee::wipeable_string seed;
bool ready, multisig;
if (m_wallet->key_on_device())
@@ -608,7 +673,8 @@ bool simple_wallet::print_seed(bool encrypted)
fail_msg_writer() << tr("wallet is watch-only and has no seed");
return true;
}
- if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
+
+ SCOPED_WALLET_UNLOCK();
multisig = m_wallet->multisig(&ready);
if (multisig)
@@ -628,7 +694,7 @@ bool simple_wallet::print_seed(bool encrypted)
epee::wipeable_string seed_pass;
if (encrypted)
{
- auto pwd_container = password_prompter(tr("Enter optional seed encryption passphrase, empty to see raw seed"), true);
+ auto pwd_container = password_prompter(tr("Enter optional seed offset passphrase, empty to see raw seed"), true);
if (std::cin.eof() || !pwd_container)
return true;
seed_pass = pwd_container->password();
@@ -677,22 +743,36 @@ bool simple_wallet::seed_set_language(const std::vector<std::string> &args/* = s
fail_msg_writer() << tr("wallet is watch-only and has no seed");
return true;
}
- if (!m_wallet->is_deterministic())
- {
- fail_msg_writer() << tr("wallet is non-deterministic and has no seed");
- return true;
- }
-
- const auto pwd_container = get_and_verify_password();
- if (pwd_container)
+
+ epee::wipeable_string password;
{
- std::string mnemonic_language = get_mnemonic_language();
- if (mnemonic_language.empty())
+ SCOPED_WALLET_UNLOCK();
+
+ if (!m_wallet->is_deterministic())
+ {
+ fail_msg_writer() << tr("wallet is non-deterministic and has no seed");
return true;
+ }
- m_wallet->set_seed_language(std::move(mnemonic_language));
- m_wallet->rewrite(m_wallet_file, pwd_container->password());
+ // we need the password, even if ask-password is unset
+ if (!pwd_container)
+ {
+ pwd_container = get_and_verify_password();
+ if (pwd_container == boost::none)
+ {
+ fail_msg_writer() << tr("Incorrect password");
+ return true;
+ }
+ }
+ password = pwd_container->password();
}
+
+ std::string mnemonic_language = get_mnemonic_language();
+ if (mnemonic_language.empty())
+ return true;
+
+ m_wallet->set_seed_language(std::move(mnemonic_language));
+ m_wallet->rewrite(m_wallet_file, password);
return true;
}
@@ -713,8 +793,7 @@ bool simple_wallet::change_password(const std::vector<std::string> &args)
try
{
- m_wallet->rewrite(m_wallet_file, pwd_container->password());
- m_wallet->store();
+ m_wallet->change_password(m_wallet_file, orig_pwd_container->password(), pwd_container->password());
}
catch (const tools::error::wallet_logic_error& e)
{
@@ -817,12 +896,7 @@ bool simple_wallet::prepare_multisig(const std::vector<std::string> &args)
return true;
}
- const auto orig_pwd_container = get_and_verify_password();
- if(orig_pwd_container == boost::none)
- {
- fail_msg_writer() << tr("Your password is incorrect.");
- return true;
- }
+ SCOPED_WALLET_UNLOCK();
std::string multisig_info = m_wallet->get_multisig_info();
success_msg_writer() << multisig_info;
@@ -855,13 +929,6 @@ bool simple_wallet::make_multisig(const std::vector<std::string> &args)
return true;
}
- const auto orig_pwd_container = get_and_verify_password();
- if(orig_pwd_container == boost::none)
- {
- fail_msg_writer() << tr("Your original password was incorrect.");
- return true;
- }
-
if (args.size() < 2)
{
fail_msg_writer() << tr("usage: make_multisig <threshold> <multisiginfo1> [<multisiginfo2>...]");
@@ -876,6 +943,13 @@ bool simple_wallet::make_multisig(const std::vector<std::string> &args)
return true;
}
+ const auto orig_pwd_container = get_and_verify_password();
+ if(orig_pwd_container == boost::none)
+ {
+ fail_msg_writer() << tr("Your original password was incorrect.");
+ return true;
+ }
+
LOCK_IDLE_SCOPE();
try
@@ -917,6 +991,14 @@ bool simple_wallet::finalize_multisig(const std::vector<std::string> &args)
fail_msg_writer() << tr("command not supported by HW wallet");
return true;
}
+
+ const auto pwd_container = get_and_verify_password();
+ if(pwd_container == boost::none)
+ {
+ fail_msg_writer() << tr("Your original password was incorrect.");
+ return true;
+ }
+
if (!m_wallet->multisig(&ready))
{
fail_msg_writer() << tr("This wallet is not multisig");
@@ -928,12 +1010,7 @@ bool simple_wallet::finalize_multisig(const std::vector<std::string> &args)
return true;
}
- const auto orig_pwd_container = get_and_verify_password();
- if(orig_pwd_container == boost::none)
- {
- fail_msg_writer() << tr("Your original password was incorrect.");
- return true;
- }
+ LOCK_IDLE_SCOPE();
if (args.size() < 2)
{
@@ -943,7 +1020,7 @@ bool simple_wallet::finalize_multisig(const std::vector<std::string> &args)
try
{
- if (!m_wallet->finalize_multisig(orig_pwd_container->password(), args))
+ if (!m_wallet->finalize_multisig(pwd_container->password(), args))
{
fail_msg_writer() << tr("Failed to finalize multisig");
return true;
@@ -981,8 +1058,8 @@ bool simple_wallet::export_multisig(const std::vector<std::string> &args)
fail_msg_writer() << tr("usage: export_multisig_info <filename>");
return true;
}
- if (m_wallet->ask_password() && !get_and_verify_password())
- return true;
+
+ SCOPED_WALLET_UNLOCK();
const std::string filename = args[0];
if (m_wallet->confirm_export_overwrite() && !check_file_overwrite(filename))
@@ -1033,8 +1110,8 @@ bool simple_wallet::import_multisig(const std::vector<std::string> &args)
fail_msg_writer() << tr("usage: import_multisig_info <filename1> [<filename2>...] - one for each other participant");
return true;
}
- if (m_wallet->ask_password() && !get_and_verify_password())
- return true;
+
+ SCOPED_WALLET_UNLOCK();
std::vector<cryptonote::blobdata> info;
for (size_t n = 0; n < args.size(); ++n)
@@ -1050,11 +1127,11 @@ bool simple_wallet::import_multisig(const std::vector<std::string> &args)
info.push_back(std::move(data));
}
- LOCK_IDLE_SCOPE();
-
// all read and parsed, actually import
try
{
+ m_in_manual_refresh.store(true, std::memory_order_relaxed);
+ epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){m_in_manual_refresh.store(false, std::memory_order_relaxed);});
size_t n_outputs = m_wallet->import_multisig(info);
// Clear line "Height xxx of xxx"
std::cout << "\r \r";
@@ -1112,7 +1189,8 @@ bool simple_wallet::sign_multisig(const std::vector<std::string> &args)
fail_msg_writer() << tr("usage: sign_multisig <filename>");
return true;
}
- if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
+
+ SCOPED_WALLET_UNLOCK();
std::string filename = args[0];
std::vector<crypto::hash> txids;
@@ -1185,7 +1263,8 @@ bool simple_wallet::submit_multisig(const std::vector<std::string> &args)
fail_msg_writer() << tr("usage: submit_multisig <filename>");
return true;
}
- if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
+
+ SCOPED_WALLET_UNLOCK();
if (!try_connect_to_daemon())
return true;
@@ -1252,7 +1331,8 @@ bool simple_wallet::export_raw_multisig(const std::vector<std::string> &args)
fail_msg_writer() << tr("usage: export_raw_multisig <filename>");
return true;
}
- if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
+
+ SCOPED_WALLET_UNLOCK();
std::string filename = args[0];
if (m_wallet->confirm_export_overwrite() && !check_file_overwrite(filename))
@@ -1825,6 +1905,7 @@ bool simple_wallet::set_auto_refresh(const std::vector<std::string> &args/* = st
if (pwd_container)
{
parse_bool_and_use(args[1], [&](bool auto_refresh) {
+ m_auto_refresh_enabled.store(false, std::memory_order_relaxed);
m_wallet->auto_refresh(auto_refresh);
m_idle_mutex.lock();
m_auto_refresh_enabled.store(auto_refresh, std::memory_order_relaxed);
@@ -1873,6 +1954,14 @@ bool simple_wallet::set_ask_password(const std::vector<std::string> &args/* = st
if (pwd_container)
{
parse_bool_and_use(args[1], [&](bool r) {
+ const bool cur_r = m_wallet->ask_password();
+ if (!m_wallet->watch_only())
+ {
+ if (cur_r && !r)
+ m_wallet->decrypt_keys(pwd_container->password());
+ else if (!cur_r && r)
+ m_wallet->encrypt_keys(pwd_container->password());
+ }
m_wallet->ask_password(r);
m_wallet->rewrite(m_wallet_file, pwd_container->password());
});
@@ -2302,6 +2391,10 @@ simple_wallet::simple_wallet()
boost::bind(&simple_wallet::get_tx_key, this, _1),
tr("get_tx_key <txid>"),
tr("Get the transaction key (r) for a given <txid>."));
+ m_cmd_binder.set_handler("set_tx_key",
+ boost::bind(&simple_wallet::set_tx_key, this, _1),
+ tr("set_tx_key <txid> <tx_key>"),
+ tr("Set the transaction key (r) for a given <txid> in case the tx was made by some other device or 3rd party wallet."));
m_cmd_binder.set_handler("check_tx_key",
boost::bind(&simple_wallet::check_tx_key, this, _1),
tr("check_tx_key <txid> <txkey> <address>"),
@@ -2334,7 +2427,7 @@ simple_wallet::simple_wallet()
tr("Check a signature proving that the owner of <address> holds at least this much, optionally with a challenge string <message>."));
m_cmd_binder.set_handler("show_transfers",
boost::bind(&simple_wallet::show_transfers, this, _1),
- tr("show_transfers [in|out|pending|failed|pool] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]"),
+ tr("show_transfers [in|out|pending|failed|pool|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]"),
tr("Show the incoming/outgoing transfers within an optional height range."));
m_cmd_binder.set_handler("unspent_outputs",
boost::bind(&simple_wallet::unspent_outputs, this, _1),
@@ -2674,28 +2767,45 @@ bool simple_wallet::ask_wallet_create_if_needed()
* \brief Prints the seed with a nice message
* \param seed seed to print
*/
-void simple_wallet::print_seed(std::string seed)
+void simple_wallet::print_seed(const epee::wipeable_string &seed)
{
success_msg_writer(true) << "\n" << tr("NOTE: the following 25 words can be used to recover access to your wallet. "
"Write them down and store them somewhere safe and secure. Please do not store them in "
"your email or on file storage services outside of your immediate control.\n");
- boost::replace_nth(seed, " ", 15, "\n");
- boost::replace_nth(seed, " ", 7, "\n");
// don't log
- std::cout << seed << std::endl;
+ int space_index = 0;
+ size_t len = seed.size();
+ for (const char *ptr = seed.data(); len--; ++ptr)
+ {
+ if (*ptr == ' ')
+ {
+ if (space_index == 15 || space_index == 7)
+ putchar('\n');
+ else
+ putchar(*ptr);
+ ++space_index;
+ }
+ else
+ putchar(*ptr);
+ }
+ putchar('\n');
+ fflush(stdout);
}
//----------------------------------------------------------------------------------------------------
-static bool might_be_partial_seed(std::string words)
+static bool might_be_partial_seed(const epee::wipeable_string &words)
{
- std::vector<std::string> seed;
+ std::vector<epee::wipeable_string> seed;
- boost::algorithm::trim(words);
- boost::split(seed, words, boost::is_any_of(" "), boost::token_compress_on);
+ words.split(seed);
return seed.size() < 24;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
+ epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){
+ m_electrum_seed.wipe();
+ });
+
const bool testnet = tools::wallet2::has_testnet_option(vm);
const bool stagenet = tools::wallet2::has_stagenet_option(vm);
if (testnet && stagenet)
@@ -2705,7 +2815,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
const network_type nettype = testnet ? TESTNET : stagenet ? STAGENET : MAINNET;
- std::string multisig_keys;
+ epee::wipeable_string multisig_keys;
if (!handle_command_line(vm))
return false;
@@ -2747,8 +2857,8 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
if (m_restore_multisig_wallet)
{
- const char *prompt = "Specify multisig seed: ";
- m_electrum_seed = input_line(prompt);
+ const char *prompt = "Specify multisig seed";
+ m_electrum_seed = input_secure_line(prompt);
if (std::cin.eof())
return false;
if (m_electrum_seed.empty())
@@ -2762,8 +2872,8 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
m_electrum_seed = "";
do
{
- const char *prompt = m_electrum_seed.empty() ? "Specify Electrum seed: " : "Electrum seed continued: ";
- std::string electrum_seed = input_line(prompt);
+ const char *prompt = m_electrum_seed.empty() ? "Specify Electrum seed" : "Electrum seed continued";
+ epee::wipeable_string electrum_seed = input_secure_line(prompt);
if (std::cin.eof())
return false;
if (electrum_seed.empty())
@@ -2771,18 +2881,21 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
fail_msg_writer() << tr("specify a recovery parameter with the --electrum-seed=\"words list here\"");
return false;
}
- m_electrum_seed += electrum_seed + " ";
+ m_electrum_seed += electrum_seed;
+ m_electrum_seed += ' ';
} while (might_be_partial_seed(m_electrum_seed));
}
}
if (m_restore_multisig_wallet)
{
- if (!epee::string_tools::parse_hexstr_to_binbuff(m_electrum_seed, multisig_keys))
+ const boost::optional<epee::wipeable_string> parsed = m_electrum_seed.parse_hexstr();
+ if (!parsed)
{
fail_msg_writer() << tr("Multisig seed failed verification");
return false;
}
+ multisig_keys = *parsed;
}
else
{
@@ -2793,7 +2906,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
}
- auto pwd_container = password_prompter(tr("Enter seed encryption passphrase, empty if none"), false);
+ auto pwd_container = password_prompter(tr("Enter seed offset passphrase, empty if none"), false);
if (std::cin.eof() || !pwd_container)
return false;
epee::wipeable_string seed_pass = pwd_container->password();
@@ -2804,12 +2917,13 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
crypto::secret_key key;
crypto::cn_slow_hash(seed_pass.data(), seed_pass.size(), (crypto::hash&)key);
sc_reduce32((unsigned char*)key.data);
- multisig_keys = m_wallet->decrypt(multisig_keys, key, true);
+ multisig_keys = m_wallet->decrypt<epee::wipeable_string>(std::string(multisig_keys.data(), multisig_keys.size()), key, true);
}
else
m_recovery_key = cryptonote::decrypt_key(m_recovery_key, seed_pass);
}
}
+ epee::wipeable_string password;
if (!m_generate_from_view_key.empty())
{
m_wallet_file = m_generate_from_view_key;
@@ -2862,8 +2976,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
return false;
}
- bool r = new_wallet(vm, info.address, boost::none, viewkey);
+ auto r = new_wallet(vm, info.address, boost::none, viewkey);
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
+ password = *r;
}
else if (!m_generate_from_spend_key.empty())
{
@@ -2881,8 +2996,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
fail_msg_writer() << tr("failed to parse spend key secret key");
return false;
}
- bool r = new_wallet(vm, m_recovery_key, true, false, "");
+ auto r = new_wallet(vm, m_recovery_key, true, false, "");
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
+ password = *r;
}
else if (!m_generate_from_keys.empty())
{
@@ -2959,8 +3075,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
fail_msg_writer() << tr("view key does not match standard address");
return false;
}
- bool r = new_wallet(vm, info.address, spendkey, viewkey);
+ auto r = new_wallet(vm, info.address, spendkey, viewkey);
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
+ password = *r;
}
// Asks user for all the data required to merge secret keys from multisig wallets into one master wallet, which then gets full control of the multisig wallet. The resulting wallet will be the same as any other regular wallet.
@@ -3093,8 +3210,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
// create wallet
- bool r = new_wallet(vm, info.address, spendkey, viewkey);
+ auto r = new_wallet(vm, info.address, spendkey, viewkey);
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
+ password = *r;
}
else if (!m_generate_from_json.empty())
@@ -3102,7 +3220,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
m_wallet_file = m_generate_from_json;
try
{
- m_wallet = tools::wallet2::make_from_json(vm, m_wallet_file, password_prompter);
+ m_wallet = tools::wallet2::make_from_json(vm, false, m_wallet_file, password_prompter);
}
catch (const std::exception &e)
{
@@ -3116,8 +3234,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
m_wallet_file = m_generate_from_device;
// create wallet
- bool r = new_wallet(vm, "Ledger");
+ auto r = new_wallet(vm, "Ledger");
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
+ password = *r;
// if no block_height is specified, assume its a new account and start it "now"
if(m_wallet->get_refresh_from_block_height() == 0) {
{
@@ -3142,12 +3261,13 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
return false;
}
m_wallet_file = m_generate_new;
- bool r;
+ boost::optional<epee::wipeable_string> r;
if (m_restore_multisig_wallet)
r = new_wallet(vm, multisig_keys, old_language);
else
r = new_wallet(vm, m_recovery_key, m_restore_deterministic_wallet, m_non_deterministic, old_language);
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
+ password = *r;
}
if (m_restoring && m_generate_from_json.empty() && m_generate_from_device.empty())
@@ -3229,6 +3349,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
m_wallet->set_refresh_from_block_height(m_restore_height);
}
+ m_wallet->rewrite(m_wallet_file, password);
}
else
{
@@ -3348,14 +3469,16 @@ bool simple_wallet::try_connect_to_daemon(bool silent, uint32_t* version)
*/
std::string simple_wallet::get_mnemonic_language()
{
- std::vector<std::string> language_list;
+ std::vector<std::string> language_list_self, language_list_english;
+ const std::vector<std::string> &language_list = m_use_english_language_names ? language_list_english : language_list_self;
std::string language_choice;
int language_number = -1;
- crypto::ElectrumWords::get_language_list(language_list, m_use_english_language_names);
+ crypto::ElectrumWords::get_language_list(language_list_self, false);
+ crypto::ElectrumWords::get_language_list(language_list_english, true);
std::cout << tr("List of available languages for your wallet's seed:") << std::endl;
std::cout << tr("If your display freezes, exit blind with ^C, then run again with --use-english-language-names") << std::endl;
int ii;
- std::vector<std::string>::iterator it;
+ std::vector<std::string>::const_iterator it;
for (it = language_list.begin(), ii = 0; it != language_list.end(); it++, ii++)
{
std::cout << ii << " : " << *it << std::endl;
@@ -3379,7 +3502,7 @@ std::string simple_wallet::get_mnemonic_language()
fail_msg_writer() << tr("invalid language choice entered. Please try again.\n");
}
}
- return language_list[language_number];
+ return language_list_self[language_number];
}
//----------------------------------------------------------------------------------------------------
boost::optional<tools::password_container> simple_wallet::get_and_verify_password() const
@@ -3396,15 +3519,16 @@ boost::optional<tools::password_container> simple_wallet::get_and_verify_passwor
return pwd_container;
}
//----------------------------------------------------------------------------------------------------
-bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
+boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
const crypto::secret_key& recovery_key, bool recover, bool two_random, const std::string &old_language)
{
- auto rc = tools::wallet2::make_new(vm, password_prompter);
+ auto rc = tools::wallet2::make_new(vm, false, password_prompter);
m_wallet = std::move(rc.first);
if (!m_wallet)
{
- return false;
+ return {};
}
+ epee::wipeable_string password = rc.second.password();
if (!m_subaddress_lookahead.empty())
{
@@ -3440,7 +3564,7 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
}
mnemonic_language = get_mnemonic_language();
if (mnemonic_language.empty())
- return false;
+ return {};
}
m_wallet->set_seed_language(mnemonic_language);
@@ -3453,16 +3577,19 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
recovery_val = m_wallet->generate(m_wallet_file, std::move(rc.second).password(), recovery_key, recover, two_random, create_address_file);
message_writer(console_color_white, true) << tr("Generated new wallet: ")
<< m_wallet->get_account().get_public_address_str(m_wallet->nettype());
- std::cout << tr("View key: ") << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_view_secret_key) << ENDL;
+ PAUSE_READLINE();
+ std::cout << tr("View key: ");
+ print_secret_key(m_wallet->get_account().get_keys().m_view_secret_key);
+ putchar('\n');
}
catch (const std::exception& e)
{
fail_msg_writer() << tr("failed to generate new wallet: ") << e.what();
- return false;
+ return {};
}
// convert rng value to electrum-style word list
- std::string electrum_words;
+ epee::wipeable_string electrum_words;
crypto::ElectrumWords::bytes_to_words(recovery_val, electrum_words, mnemonic_language);
@@ -3483,19 +3610,20 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
}
success_msg_writer() << "**********************************************************************";
- return true;
+ return std::move(password);
}
//----------------------------------------------------------------------------------------------------
-bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
+boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
const cryptonote::account_public_address& address, const boost::optional<crypto::secret_key>& spendkey,
const crypto::secret_key& viewkey)
{
- auto rc = tools::wallet2::make_new(vm, password_prompter);
+ auto rc = tools::wallet2::make_new(vm, false, password_prompter);
m_wallet = std::move(rc.first);
if (!m_wallet)
{
- return false;
+ return {};
}
+ epee::wipeable_string password = rc.second.password();
if (!m_subaddress_lookahead.empty())
{
@@ -3525,22 +3653,23 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
catch (const std::exception& e)
{
fail_msg_writer() << tr("failed to generate new wallet: ") << e.what();
- return false;
+ return {};
}
- return true;
+ return std::move(password);
}
//----------------------------------------------------------------------------------------------------
-bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
+boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
const std::string &device_name) {
- auto rc = tools::wallet2::make_new(vm, password_prompter);
+ auto rc = tools::wallet2::make_new(vm, false, password_prompter);
m_wallet = std::move(rc.first);
if (!m_wallet)
{
- return false;
+ return {};
}
+ epee::wipeable_string password = rc.second.password();
if (!m_subaddress_lookahead.empty())
{
@@ -3561,21 +3690,22 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
catch (const std::exception& e)
{
fail_msg_writer() << tr("failed to generate new wallet: ") << e.what();
- return false;
+ return {};
}
- return true;
+ return std::move(password);
}
//----------------------------------------------------------------------------------------------------
-bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
- const std::string &multisig_keys, const std::string &old_language)
+boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
+ const epee::wipeable_string &multisig_keys, const std::string &old_language)
{
- auto rc = tools::wallet2::make_new(vm, password_prompter);
+ auto rc = tools::wallet2::make_new(vm, false, password_prompter);
m_wallet = std::move(rc.first);
if (!m_wallet)
{
- return false;
+ return {};
}
+ epee::wipeable_string password = rc.second.password();
if (!m_subaddress_lookahead.empty())
{
@@ -3605,7 +3735,7 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
if (!m_wallet->multisig(&ready, &threshold, &total) || !ready)
{
fail_msg_writer() << tr("failed to generate new mutlisig wallet");
- return false;
+ return {};
}
message_writer(console_color_white, true) << boost::format(tr("Generated new %u/%u multisig wallet: ")) % threshold % total
<< m_wallet->get_account().get_public_address_str(m_wallet->nettype());
@@ -3613,10 +3743,10 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
catch (const std::exception& e)
{
fail_msg_writer() << tr("failed to generate new wallet: ") << e.what();
- return false;
+ return {};
}
- return true;
+ return std::move(password);
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
@@ -3640,7 +3770,7 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
epee::wipeable_string password;
try
{
- auto rc = tools::wallet2::make_from_file(vm, m_wallet_file, password_prompter);
+ auto rc = tools::wallet2::make_from_file(vm, false, m_wallet_file, password_prompter);
m_wallet = std::move(rc.first);
password = std::move(std::move(rc.second).password());
if (!m_wallet)
@@ -3667,7 +3797,12 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
// NOTE: this is_deprecated() refers to the wallet file format before becoming JSON. It does not refer to the "old english" seed words form of "deprecated" used elsewhere.
if (m_wallet->is_deprecated())
{
- if (m_wallet->is_deterministic())
+ bool is_deterministic;
+ {
+ SCOPED_WALLET_UNLOCK();
+ is_deterministic = m_wallet->is_deterministic();
+ }
+ if (is_deterministic)
{
message_writer(console_color_green, false) << "\n" << tr("You had been using "
"a deprecated version of the wallet. Please proceed to upgrade your wallet.\n");
@@ -3678,7 +3813,7 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
m_wallet->rewrite(m_wallet_file, password);
// Display the seed
- std::string seed;
+ epee::wipeable_string seed;
m_wallet->get_seed(seed);
print_seed(seed);
}
@@ -3905,7 +4040,7 @@ bool simple_wallet::set_daemon(const std::vector<std::string>& args)
daemon_url = args[0];
}
LOCK_IDLE_SCOPE();
- m_wallet->init(daemon_url);
+ m_wallet->init(false, daemon_url);
if (args.size() == 2)
{
@@ -4019,6 +4154,32 @@ void simple_wallet::on_skip_transaction(uint64_t height, const crypto::hash &txi
{
}
//----------------------------------------------------------------------------------------------------
+boost::optional<epee::wipeable_string> simple_wallet::on_get_password(const char *reason)
+{
+ // can't ask for password from a background thread
+ if (!m_in_manual_refresh.load(std::memory_order_relaxed))
+ {
+ message_writer(console_color_red, false) << tr("Password needed - use the refresh command");
+ m_cmd_binder.print_prompt();
+ return boost::none;
+ }
+
+#ifdef HAVE_READLINE
+ rdln::suspend_readline pause_readline;
+#endif
+ std::string msg = tr("Enter password");
+ if (reason && *reason)
+ msg += std::string(" (") + reason + ")";
+ auto pwd_container = tools::password_container::prompt(false, msg.c_str());
+ if (!pwd_container)
+ {
+ MERROR("Failed to read password");
+ return boost::none;
+ }
+
+ return pwd_container->password();
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::refresh_main(uint64_t start_height, bool reset, bool is_init)
{
if (!try_connect_to_daemon(is_init))
@@ -4494,11 +4655,10 @@ bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending
bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::string> &args_)
{
// "transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <amount> [<payment_id>]"
- if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
if (!try_connect_to_daemon())
return true;
- LOCK_IDLE_SCOPE();
+ SCOPED_WALLET_UNLOCK();
std::vector<std::string> local_args = args_;
@@ -4901,11 +5061,11 @@ bool simple_wallet::locked_sweep_all(const std::vector<std::string> &args_)
bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
{
- if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
if (!try_connect_to_daemon())
return true;
- LOCK_IDLE_SCOPE();
+ SCOPED_WALLET_UNLOCK();
+
try
{
// figure out what tx will be necessary
@@ -5018,7 +5178,6 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
return true;
}
- if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
if (!try_connect_to_daemon())
return true;
@@ -5182,7 +5341,7 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
}
}
- LOCK_IDLE_SCOPE();
+ SCOPED_WALLET_UNLOCK();
try
{
@@ -5284,7 +5443,7 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
//----------------------------------------------------------------------------------------------------
bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
{
- if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
+ SCOPED_WALLET_UNLOCK();
if (!try_connect_to_daemon())
return true;
@@ -5710,7 +5869,8 @@ bool simple_wallet::sign_transfer(const std::vector<std::string> &args_)
fail_msg_writer() << tr("usage: sign_transfer [export_raw]");
return true;
}
- if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
+
+ SCOPED_WALLET_UNLOCK();
const bool export_raw = args_.size() == 1;
std::vector<tools::wallet2::pending_tx> ptx;
@@ -5799,7 +5959,6 @@ bool simple_wallet::get_tx_key(const std::vector<std::string> &args_)
fail_msg_writer() << tr("usage: get_tx_key <txid>");
return true;
}
- if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
crypto::hash txid;
if (!epee::string_tools::hex_to_pod(local_args[0], txid))
@@ -5808,7 +5967,7 @@ bool simple_wallet::get_tx_key(const std::vector<std::string> &args_)
return true;
}
- LOCK_IDLE_SCOPE();
+ SCOPED_WALLET_UNLOCK();
crypto::secret_key tx_key;
std::vector<crypto::secret_key> additional_tx_keys;
@@ -5828,6 +5987,64 @@ bool simple_wallet::get_tx_key(const std::vector<std::string> &args_)
}
}
//----------------------------------------------------------------------------------------------------
+bool simple_wallet::set_tx_key(const std::vector<std::string> &args_)
+{
+ std::vector<std::string> local_args = args_;
+
+ if(local_args.size() != 2) {
+ fail_msg_writer() << tr("usage: set_tx_key <txid> <tx_key>");
+ return true;
+ }
+
+ crypto::hash txid;
+ if (!epee::string_tools::hex_to_pod(local_args[0], txid))
+ {
+ fail_msg_writer() << tr("failed to parse txid");
+ return true;
+ }
+
+ crypto::secret_key tx_key;
+ std::vector<crypto::secret_key> additional_tx_keys;
+ try
+ {
+ if (!epee::string_tools::hex_to_pod(local_args[1].substr(0, 64), tx_key))
+ {
+ fail_msg_writer() << tr("failed to parse tx_key");
+ return true;
+ }
+ while(true)
+ {
+ local_args[1] = local_args[1].substr(64);
+ if (local_args[1].empty())
+ break;
+ additional_tx_keys.resize(additional_tx_keys.size() + 1);
+ if (!epee::string_tools::hex_to_pod(local_args[1].substr(0, 64), additional_tx_keys.back()))
+ {
+ fail_msg_writer() << tr("failed to parse tx_key");
+ return true;
+ }
+ }
+ }
+ catch (const std::out_of_range &e)
+ {
+ fail_msg_writer() << tr("failed to parse tx_key");
+ return true;
+ }
+
+ LOCK_IDLE_SCOPE();
+
+ try
+ {
+ m_wallet->set_tx_key(txid, tx_key, additional_tx_keys);
+ success_msg_writer() << tr("Tx key successfully stored.");
+ }
+ catch (const std::exception &e)
+ {
+ fail_msg_writer() << tr("Failed to store tx key: ") << e.what();
+ }
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::get_tx_proof(const std::vector<std::string> &args)
{
if (m_wallet->key_on_device())
@@ -5855,7 +6072,7 @@ bool simple_wallet::get_tx_proof(const std::vector<std::string> &args)
return true;
}
- if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
+ SCOPED_WALLET_UNLOCK();
try
{
@@ -6070,7 +6287,7 @@ bool simple_wallet::get_spend_proof(const std::vector<std::string> &args)
return true;
}
- if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
+ SCOPED_WALLET_UNLOCK();
try
{
@@ -6165,9 +6382,7 @@ bool simple_wallet::get_reserve_proof(const std::vector<std::string> &args)
return true;
}
- if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
-
- LOCK_IDLE_SCOPE();
+ SCOPED_WALLET_UNLOCK();
try
{
@@ -6280,12 +6495,13 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
bool pending = true;
bool failed = true;
bool pool = true;
+ bool coinbase = true;
uint64_t min_height = 0;
uint64_t max_height = (uint64_t)-1;
boost::optional<uint32_t> subaddr_index;
if(local_args.size() > 4) {
- fail_msg_writer() << tr("usage: show_transfers [in|out|all|pending|failed] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]");
+ fail_msg_writer() << tr("usage: show_transfers [in|out|all|pending|failed|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]");
return true;
}
@@ -6298,19 +6514,24 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
local_args.erase(local_args.begin());
}
else if (local_args[0] == "out" || local_args[0] == "outgoing") {
- in = pool = false;
+ in = pool = coinbase = false;
local_args.erase(local_args.begin());
}
else if (local_args[0] == "pending") {
- in = out = failed = false;
+ in = out = failed = coinbase = false;
local_args.erase(local_args.begin());
}
else if (local_args[0] == "failed") {
- in = out = pending = pool = false;
+ in = out = pending = pool = coinbase = false;
local_args.erase(local_args.begin());
}
else if (local_args[0] == "pool") {
- in = out = pending = failed = false;
+ in = out = pending = failed = coinbase = false;
+ local_args.erase(local_args.begin());
+ }
+ else if (local_args[0] == "coinbase") {
+ in = out = pending = failed = pool = false;
+ coinbase = true;
local_args.erase(local_args.begin());
}
else if (local_args[0] == "all" || local_args[0] == "both") {
@@ -6351,20 +6572,23 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
local_args.erase(local_args.begin());
}
- std::multimap<uint64_t, std::pair<bool,std::string>> output;
+ std::multimap<uint64_t, std::tuple<epee::console_colors, std::string, std::string>> output;
PAUSE_READLINE();
- if (in) {
+ if (in || coinbase) {
std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> payments;
m_wallet->get_payments(payments, min_height, max_height, m_current_subaddress_account, subaddr_indices);
for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) {
const tools::wallet2::payment_details &pd = i->second;
+ if (!pd.m_coinbase && !in)
+ continue;
std::string payment_id = string_tools::pod_to_hex(i->first);
if (payment_id.substr(16).find_first_not_of('0') == std::string::npos)
payment_id = payment_id.substr(0,16);
std::string note = m_wallet->get_tx_note(pd.m_tx_hash);
- output.insert(std::make_pair(pd.m_block_height, std::make_pair(true, (boost::format("%25.25s %20.20s %s %s %d %s %s") % get_human_readable_timestamp(pd.m_timestamp) % print_money(pd.m_amount) % string_tools::pod_to_hex(pd.m_tx_hash) % payment_id % pd.m_subaddr_index.minor % "-" % note).str())));
+ const std::string type = pd.m_coinbase ? tr("block") : tr("in");
+ output.insert(std::make_pair(pd.m_block_height, std::make_tuple(epee::console_color_green, type, (boost::format("%25.25s %20.20s %s %s %d %s %s") % get_human_readable_timestamp(pd.m_timestamp) % print_money(pd.m_amount) % string_tools::pod_to_hex(pd.m_tx_hash) % payment_id % pd.m_subaddr_index.minor % "-" % note).str())));
}
}
@@ -6397,20 +6621,23 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
if (payment_id.substr(16).find_first_not_of('0') == std::string::npos)
payment_id = payment_id.substr(0,16);
std::string note = m_wallet->get_tx_note(i->first);
- output.insert(std::make_pair(pd.m_block_height, std::make_pair(false, (boost::format("%25.25s %20.20s %s %s %14.14s %s %s - %s") % get_human_readable_timestamp(pd.m_timestamp) % print_money(pd.m_amount_in - change - fee) % string_tools::pod_to_hex(i->first) % payment_id % print_money(fee) % dests % print_subaddr_indices(pd.m_subaddr_indices) % note).str())));
+ output.insert(std::make_pair(pd.m_block_height, std::make_tuple(epee::console_color_magenta, tr("out"), (boost::format("%25.25s %20.20s %s %s %14.14s %s %s - %s") % get_human_readable_timestamp(pd.m_timestamp) % print_money(pd.m_amount_in - change - fee) % string_tools::pod_to_hex(i->first) % payment_id % print_money(fee) % dests % print_subaddr_indices(pd.m_subaddr_indices) % note).str())));
}
}
// print in and out sorted by height
- for (std::map<uint64_t, std::pair<bool, std::string>>::const_iterator i = output.begin(); i != output.end(); ++i) {
- message_writer(i->second.first ? console_color_green : console_color_magenta, false) <<
+ for (std::multimap<uint64_t, std::tuple<epee::console_colors, std::string, std::string>>::const_iterator i = output.begin(); i != output.end(); ++i) {
+ message_writer(std::get<0>(i->second), false) <<
boost::format("%8.8llu %6.6s %s") %
- ((unsigned long long)i->first) % (i->second.first ? tr("in") : tr("out")) % i->second.second;
+ ((unsigned long long)i->first) % std::get<1>(i->second) % std::get<2>(i->second);
}
if (pool) {
try
{
+ m_in_manual_refresh.store(true, std::memory_order_relaxed);
+ epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){m_in_manual_refresh.store(false, std::memory_order_relaxed);});
+
m_wallet->update_pool_state();
std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>> payments;
m_wallet->get_unconfirmed_payments(payments, m_current_subaddress_account, subaddr_indices);
@@ -6464,7 +6691,7 @@ bool simple_wallet::unspent_outputs(const std::vector<std::string> &args_)
auto local_args = args_;
std::set<uint32_t> subaddr_indices;
- if (local_args.size() > 0 && local_args[0].substr(0, 6) != "index=")
+ if (local_args.size() > 0 && local_args[0].substr(0, 6) == "index=")
{
if (!parse_subaddress_indices(local_args[0], subaddr_indices))
return true;
@@ -7259,7 +7486,8 @@ bool simple_wallet::sign(const std::vector<std::string> &args)
fail_msg_writer() << tr("This wallet is multisig and cannot sign");
return true;
}
- if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
+
+ SCOPED_WALLET_UNLOCK();
std::string filename = args[0];
std::string data;
bool r = epee::file_io_utils::load_file_to_string(filename, data);
@@ -7328,14 +7556,14 @@ bool simple_wallet::export_key_images(const std::vector<std::string> &args)
fail_msg_writer() << tr("wallet is watch-only and cannot export key images");
return true;
}
- if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
+
+ SCOPED_WALLET_UNLOCK();
std::string filename = args[0];
if (m_wallet->confirm_export_overwrite() && !check_file_overwrite(filename))
return true;
try
{
- LOCK_IDLE_SCOPE();
if (!m_wallet->export_key_images(filename))
{
fail_msg_writer() << tr("failed to save file ") << filename;
@@ -7407,12 +7635,12 @@ bool simple_wallet::export_outputs(const std::vector<std::string> &args)
fail_msg_writer() << tr("usage: export_outputs <filename>");
return true;
}
- if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
+
+ SCOPED_WALLET_UNLOCK();
std::string filename = args[0];
if (m_wallet->confirm_export_overwrite() && !check_file_overwrite(filename))
return true;
- LOCK_IDLE_SCOPE();
try
{
std::string data = m_wallet->export_outputs_to_str();
@@ -7458,7 +7686,7 @@ bool simple_wallet::import_outputs(const std::vector<std::string> &args)
try
{
- LOCK_IDLE_SCOPE();
+ SCOPED_WALLET_UNLOCK();
size_t n_outputs = m_wallet->import_outputs_from_str(data);
success_msg_writer() << boost::lexical_cast<std::string>(n_outputs) << " outputs imported";
}
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index b8f7bb84b..99fc19c00 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -44,6 +44,7 @@
#include "cryptonote_basic/cryptonote_basic_impl.h"
#include "wallet/wallet2.h"
#include "console_handler.h"
+#include "wipeable_string.h"
#include "common/i18n.h"
#include "common/password.h"
#include "crypto/crypto.h" // for definition of crypto::secret_key
@@ -91,13 +92,13 @@ namespace cryptonote
//! \return Prompts user for password and verifies against local file. Logs on error and returns `none`
boost::optional<tools::password_container> get_and_verify_password() const;
- bool new_wallet(const boost::program_options::variables_map& vm, const crypto::secret_key& recovery_key,
+ boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm, const crypto::secret_key& recovery_key,
bool recover, bool two_random, const std::string &old_language);
- bool new_wallet(const boost::program_options::variables_map& vm, const cryptonote::account_public_address& address,
+ boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm, const cryptonote::account_public_address& address,
const boost::optional<crypto::secret_key>& spendkey, const crypto::secret_key& viewkey);
- bool new_wallet(const boost::program_options::variables_map& vm,
- const std::string &multisig_keys, const std::string &old_language);
- bool new_wallet(const boost::program_options::variables_map& vm, const std::string& device_name);
+ boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm,
+ const epee::wipeable_string &multisig_keys, const std::string &old_language);
+ boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm, const std::string& device_name);
bool open_wallet(const boost::program_options::variables_map& vm);
bool close_wallet();
@@ -177,6 +178,7 @@ namespace cryptonote
bool rescan_spent(const std::vector<std::string> &args);
bool set_log(const std::vector<std::string> &args);
bool get_tx_key(const std::vector<std::string> &args);
+ bool set_tx_key(const std::vector<std::string> &args);
bool check_tx_key(const std::vector<std::string> &args);
bool get_tx_proof(const std::vector<std::string> &args);
bool check_tx_proof(const std::vector<std::string> &args);
@@ -237,7 +239,7 @@ namespace cryptonote
* \brief Prints the seed with a nice message
* \param seed seed to print
*/
- void print_seed(std::string seed);
+ void print_seed(const epee::wipeable_string &seed);
/*!
* \brief Gets the word seed language from the user.
@@ -260,6 +262,7 @@ namespace cryptonote
virtual void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index);
virtual void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx, uint64_t amount, const cryptonote::transaction& spend_tx, const cryptonote::subaddress_index& subaddr_index);
virtual void on_skip_transaction(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx);
+ virtual boost::optional<epee::wipeable_string> on_get_password(const char *reason);
//----------------------------------------------------------
friend class refresh_progress_reporter_t;
@@ -328,7 +331,7 @@ namespace cryptonote
std::string m_import_path;
std::string m_subaddress_lookahead;
- std::string m_electrum_seed; // electrum-style seed parameter
+ epee::wipeable_string m_electrum_seed; // electrum-style seed parameter
crypto::secret_key m_recovery_key; // recovery key (used as random for wallet gen)
bool m_restore_deterministic_wallet; // recover flag