aboutsummaryrefslogtreecommitdiff
path: root/src/simplewallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/simplewallet')
-rw-r--r--src/simplewallet/simplewallet.cpp482
-rw-r--r--src/simplewallet/simplewallet.h10
2 files changed, 321 insertions, 171 deletions
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index e07c7e49b..f5aeabded 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -95,17 +95,18 @@ typedef cryptonote::simple_wallet sw;
m_auto_refresh_enabled.store(false, std::memory_order_relaxed); \
/* stop any background refresh, and take over */ \
m_wallet->stop(); \
- m_idle_mutex.lock(); \
- while (m_auto_refresh_refreshing) \
- m_idle_cond.notify_one(); \
- m_idle_mutex.unlock(); \
-/* if (auto_refresh_run)*/ \
- /*m_auto_refresh_thread.join();*/ \
boost::unique_lock<boost::mutex> lock(m_idle_mutex); \
+ m_idle_cond.notify_all(); \
epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ \
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,
@@ -128,8 +129,6 @@ namespace
const command_line::arg_descriptor<bool> arg_restore_deterministic_wallet = {"restore-deterministic-wallet", sw::tr("Recover wallet using Electrum-style mnemonic seed"), false};
const command_line::arg_descriptor<bool> arg_restore_multisig_wallet = {"restore-multisig-wallet", sw::tr("Recover multisig wallet using Electrum-style mnemonic seed"), false};
const command_line::arg_descriptor<bool> arg_non_deterministic = {"non-deterministic", sw::tr("Generate non-deterministic view and spend keys"), false};
- const command_line::arg_descriptor<bool> arg_trusted_daemon = {"trusted-daemon", sw::tr("Enable commands which rely on a trusted daemon"), false};
- const command_line::arg_descriptor<bool> arg_untrusted_daemon = {"untrusted-daemon", sw::tr("Disable commands which rely on a trusted daemon"), false};
const command_line::arg_descriptor<bool> arg_allow_mismatched_daemon_version = {"allow-mismatched-daemon-version", sw::tr("Allow communicating with a daemon that uses a different RPC version"), false};
const command_line::arg_descriptor<uint64_t> arg_restore_height = {"restore-height", sw::tr("Restore from specific blockchain height"), 0};
const command_line::arg_descriptor<bool> arg_do_not_relay = {"do-not-relay", sw::tr("The newly created transaction will not be relayed to the monero network"), false};
@@ -152,12 +151,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 +195,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 +552,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)
@@ -527,6 +579,18 @@ bool parse_priority(const std::string& arg, uint32_t& priority)
return false;
}
+std::string join_priority_strings(const char *delimiter)
+{
+ std::string s;
+ for (size_t n = 0; n < allowed_priority_strings.size(); ++n)
+ {
+ if (!s.empty())
+ s += delimiter;
+ s += allowed_priority_strings[n];
+ }
+ return s;
+}
+
std::string simple_wallet::get_commands_str()
{
std::stringstream ss;
@@ -561,12 +625,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 +647,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 +665,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 +678,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)
@@ -677,22 +748,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 +798,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 +901,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 +934,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 +948,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 +996,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 +1015,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 +1025,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 +1063,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 +1115,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 +1132,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";
@@ -1065,7 +1147,7 @@ bool simple_wallet::import_multisig(const std::vector<std::string> &args)
fail_msg_writer() << tr("Failed to import multisig info: ") << e.what();
return true;
}
- if (is_daemon_trusted())
+ if (m_wallet->is_trusted_daemon())
{
try
{
@@ -1112,7 +1194,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 +1268,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;
@@ -1217,7 +1301,7 @@ bool simple_wallet::submit_multisig(const std::vector<std::string> &args)
}
catch (const std::exception &e)
{
- handle_transfer_exception(std::current_exception(), is_daemon_trusted());
+ handle_transfer_exception(std::current_exception(), m_wallet->is_trusted_daemon());
}
catch (...)
{
@@ -1252,7 +1336,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))
@@ -1777,12 +1862,12 @@ bool simple_wallet::set_default_ring_size(const std::vector<std::string> &args/*
bool simple_wallet::set_default_priority(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
- int priority = 0;
+ uint32_t priority = 0;
try
{
if (strchr(args[1].c_str(), '-'))
{
- fail_msg_writer() << tr("priority must be 0, 1, 2, 3, or 4 ");
+ fail_msg_writer() << tr("priority must be either 0, 1, 2, 3, or 4, or one of: ") << join_priority_strings(", ");
return true;
}
if (args[1] == "0")
@@ -1791,11 +1876,23 @@ bool simple_wallet::set_default_priority(const std::vector<std::string> &args/*
}
else
{
- priority = boost::lexical_cast<int>(args[1]);
- if (priority < 1 || priority > 4)
+ bool found = false;
+ for (size_t n = 0; n < allowed_priority_strings.size(); ++n)
{
- fail_msg_writer() << tr("priority must be 0, 1, 2, 3, or 4");
- return true;
+ if (allowed_priority_strings[n] == args[1])
+ {
+ found = true;
+ priority = n;
+ }
+ }
+ if (!found)
+ {
+ priority = boost::lexical_cast<int>(args[1]);
+ if (priority < 1 || priority > 4)
+ {
+ fail_msg_writer() << tr("priority must be either 0, 1, 2, 3, or 4, or one of: ") << join_priority_strings(", ");
+ return true;
+ }
}
}
@@ -1809,7 +1906,7 @@ bool simple_wallet::set_default_priority(const std::vector<std::string> &args/*
}
catch(const boost::bad_lexical_cast &)
{
- fail_msg_writer() << tr("priority must be 0, 1, 2, 3, or 4");
+ fail_msg_writer() << tr("priority must be either 0, 1, 2, 3, or 4, or one of: ") << join_priority_strings(", ");
return true;
}
catch(...)
@@ -1874,6 +1971,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());
});
@@ -2347,7 +2452,7 @@ simple_wallet::simple_wallet()
tr("Show the unspent outputs of a specified address within an optional amount range."));
m_cmd_binder.set_handler("rescan_bc",
boost::bind(&simple_wallet::rescan_blockchain, this, _1),
- tr("Rescan the blockchain from scratch."));
+ tr("Rescan the blockchain from scratch, losing any information which can not be recovered from the blockchain itself."));
m_cmd_binder.set_handler("set_tx_note",
boost::bind(&simple_wallet::set_tx_note, this, _1),
tr("set_tx_note <txid> [free text note]"),
@@ -2476,6 +2581,10 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
std::string seed_language = m_wallet->get_seed_language();
if (m_use_english_language_names)
seed_language = crypto::ElectrumWords::get_english_name_for(seed_language);
+ std::string priority_string = "invalid";
+ uint32_t priority = m_wallet->get_default_priority();
+ if (priority < allowed_priority_strings.size())
+ priority_string = allowed_priority_strings[priority];
success_msg_writer() << "seed = " << seed_language;
success_msg_writer() << "always-confirm-transfers = " << m_wallet->always_confirm_transfers();
success_msg_writer() << "print-ring-members = " << m_wallet->print_ring_members();
@@ -2483,7 +2592,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
success_msg_writer() << "default-ring-size = " << (m_wallet->default_mixin() ? m_wallet->default_mixin() + 1 : 0);
success_msg_writer() << "auto-refresh = " << m_wallet->auto_refresh();
success_msg_writer() << "refresh-type = " << get_refresh_type_name(m_wallet->get_refresh_type());
- success_msg_writer() << "priority = " << m_wallet->get_default_priority();
+ success_msg_writer() << "priority = " << priority<< " (" << priority_string << ")";
success_msg_writer() << "confirm-missing-payment-id = " << m_wallet->confirm_missing_payment_id();
success_msg_writer() << "ask-password = " << m_wallet->ask_password();
success_msg_writer() << "unit = " << cryptonote::get_unit(cryptonote::get_default_decimal_point());
@@ -2539,7 +2648,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
CHECK_SIMPLE_VARIABLE("default-ring-size", set_default_ring_size, tr("integer >= ") << MIN_RING_SIZE);
CHECK_SIMPLE_VARIABLE("auto-refresh", set_auto_refresh, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("refresh-type", set_refresh_type, tr("full (slowest, no assumptions); optimize-coinbase (fast, assumes the whole coinbase is paid to a single address); no-coinbase (fastest, assumes we receive no coinbase transaction), default (same as optimize-coinbase)"));
- CHECK_SIMPLE_VARIABLE("priority", set_default_priority, tr("0, 1, 2, 3, or 4"));
+ CHECK_SIMPLE_VARIABLE("priority", set_default_priority, tr("0, 1, 2, 3, or 4, or one of ") << join_priority_strings(", "));
CHECK_SIMPLE_VARIABLE("confirm-missing-payment-id", set_confirm_missing_payment_id, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("ask-password", set_ask_password, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("unit", set_unit, tr("monero, millinero, micronero, nanonero, piconero"));
@@ -2679,28 +2788,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)
@@ -2710,7 +2836,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;
@@ -2752,8 +2878,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())
@@ -2767,8 +2893,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())
@@ -2776,18 +2902,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
{
@@ -2809,7 +2938,7 @@ 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);
@@ -3112,7 +3241,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)
{
@@ -3260,22 +3389,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
return false;
}
- // set --trusted-daemon if local and not overridden
- if (!m_trusted_daemon)
- {
- try
- {
- m_trusted_daemon = false;
- if (tools::is_local_address(m_wallet->get_daemon_address()))
- {
- MINFO(tr("Daemon is local, assuming trusted"));
- m_trusted_daemon = true;
- }
- }
- catch (const std::exception &e) { }
- }
-
- if (!is_daemon_trusted())
+ if (!m_wallet->is_trusted_daemon())
message_writer() << (boost::format(tr("Warning: using an untrusted daemon at %s, privacy will be lessened")) % m_wallet->get_daemon_address()).str();
if (m_wallet->get_ring_database().empty())
@@ -3309,10 +3423,6 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
m_restore_deterministic_wallet = command_line::get_arg(vm, arg_restore_deterministic_wallet);
m_restore_multisig_wallet = command_line::get_arg(vm, arg_restore_multisig_wallet);
m_non_deterministic = command_line::get_arg(vm, arg_non_deterministic);
- if (!command_line::is_arg_defaulted(vm, arg_trusted_daemon) || !command_line::is_arg_defaulted(vm, arg_untrusted_daemon))
- m_trusted_daemon = command_line::get_arg(vm, arg_trusted_daemon) && !command_line::get_arg(vm, arg_untrusted_daemon);
- if (!command_line::is_arg_defaulted(vm, arg_trusted_daemon) && !command_line::is_arg_defaulted(vm, arg_untrusted_daemon))
- message_writer() << tr("--trusted-daemon and --untrusted-daemon are both seen, assuming untrusted");
m_allow_mismatched_daemon_version = command_line::get_arg(vm, arg_allow_mismatched_daemon_version);
m_restore_height = command_line::get_arg(vm, arg_restore_height);
m_do_not_relay = command_line::get_arg(vm, arg_do_not_relay);
@@ -3414,7 +3524,7 @@ boost::optional<tools::password_container> simple_wallet::get_and_verify_passwor
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)
{
@@ -3469,7 +3579,10 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr
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)
{
@@ -3478,7 +3591,7 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr
}
// 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);
@@ -3506,7 +3619,7 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr
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)
{
@@ -3552,7 +3665,7 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr
//----------------------------------------------------------------------------------------------------
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)
{
@@ -3586,9 +3699,9 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr
}
//----------------------------------------------------------------------------------------------------
boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
- const std::string &multisig_keys, const std::string &old_language)
+ 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)
{
@@ -3659,7 +3772,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)
@@ -3686,7 +3799,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");
@@ -3697,7 +3815,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);
}
@@ -3816,7 +3934,7 @@ bool simple_wallet::save_watch_only(const std::vector<std::string> &args/* = std
//----------------------------------------------------------------------------------------------------
bool simple_wallet::start_mining(const std::vector<std::string>& args)
{
- if (!is_daemon_trusted())
+ if (!m_wallet->is_trusted_daemon())
{
fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
return true;
@@ -3924,34 +4042,34 @@ 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)
{
if (args[1] == "trusted")
- m_trusted_daemon = true;
+ m_wallet->set_trusted_daemon(true);
else if (args[1] == "untrusted")
- m_trusted_daemon = false;
+ m_wallet->set_trusted_daemon(false);
else
{
fail_msg_writer() << tr("Expected trusted or untrusted, got ") << args[1] << ": assuming untrusted";
- m_trusted_daemon = false;
+ m_wallet->set_trusted_daemon(false);
}
}
else
{
- m_trusted_daemon = false;
+ m_wallet->set_trusted_daemon(false);
try
{
if (tools::is_local_address(m_wallet->get_daemon_address()))
{
MINFO(tr("Daemon is local, assuming trusted"));
- m_trusted_daemon = true;
+ m_wallet->set_trusted_daemon(true);
}
}
catch (const std::exception &e) { }
}
- success_msg_writer() << boost::format("Daemon set to %s, %s") % daemon_url % (*m_trusted_daemon ? tr("trusted") : tr("untrusted"));
+ success_msg_writer() << boost::format("Daemon set to %s, %s") % daemon_url % (m_wallet->is_trusted_daemon() ? tr("trusted") : tr("untrusted"));
} else {
fail_msg_writer() << tr("This does not seem to be a valid daemon URL.");
}
@@ -4038,6 +4156,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))
@@ -4061,7 +4205,7 @@ bool simple_wallet::refresh_main(uint64_t start_height, bool reset, bool is_init
{
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->refresh(is_daemon_trusted(), start_height, fetched_blocks);
+ m_wallet->refresh(m_wallet->is_trusted_daemon(), start_height, fetched_blocks);
ok = true;
// Clear line "Height xxx of xxx"
std::cout << "\r \r";
@@ -4352,7 +4496,7 @@ bool simple_wallet::show_blockchain_height(const std::vector<std::string>& args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::rescan_spent(const std::vector<std::string> &args)
{
- if (!is_daemon_trusted())
+ if (!m_wallet->is_trusted_daemon())
{
fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
return true;
@@ -4513,11 +4657,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_;
@@ -4701,16 +4844,16 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
return true;
}
unlock_block = bc_height + locked_blocks;
- ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, is_daemon_trusted());
+ ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices);
break;
case TransferNew:
- ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, is_daemon_trusted());
+ ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices);
break;
default:
LOG_ERROR("Unknown transfer method, using original");
/* FALLTHRU */
case TransferOriginal:
- ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra, is_daemon_trusted());
+ ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra);
break;
}
@@ -4886,7 +5029,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
}
catch (const std::exception &e)
{
- handle_transfer_exception(std::current_exception(), is_daemon_trusted());
+ handle_transfer_exception(std::current_exception(), m_wallet->is_trusted_daemon());
}
catch (...)
{
@@ -4920,15 +5063,15 @@ 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
- auto ptx_vector = m_wallet->create_unmixable_sweep_transactions(is_daemon_trusted());
+ auto ptx_vector = m_wallet->create_unmixable_sweep_transactions();
if (ptx_vector.empty())
{
@@ -5007,13 +5150,13 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
{
try
{
- m_wallet->discard_unmixable_outputs(is_daemon_trusted());
+ m_wallet->discard_unmixable_outputs();
} catch (...) {}
}
}
catch (const std::exception &e)
{
- handle_transfer_exception(std::current_exception(), is_daemon_trusted());
+ handle_transfer_exception(std::current_exception(), m_wallet->is_trusted_daemon());
}
catch (...)
{
@@ -5037,7 +5180,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;
@@ -5201,12 +5343,12 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
}
}
- LOCK_IDLE_SCOPE();
+ SCOPED_WALLET_UNLOCK();
try
{
// figure out what tx will be necessary
- auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, is_daemon_trusted());
+ auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices);
if (ptx_vector.empty())
{
@@ -5290,7 +5432,7 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
}
catch (const std::exception& e)
{
- handle_transfer_exception(std::current_exception(), is_daemon_trusted());
+ handle_transfer_exception(std::current_exception(), m_wallet->is_trusted_daemon());
}
catch (...)
{
@@ -5303,7 +5445,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;
@@ -5419,7 +5561,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
try
{
// figure out what tx will be necessary
- auto ptx_vector = m_wallet->create_transactions_single(ki, info.address, info.is_subaddress, fake_outs_count, 0 /* unlock_time */, priority, extra, is_daemon_trusted());
+ auto ptx_vector = m_wallet->create_transactions_single(ki, info.address, info.is_subaddress, fake_outs_count, 0 /* unlock_time */, priority, extra);
if (ptx_vector.empty())
{
@@ -5489,7 +5631,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
}
catch (const std::exception& e)
{
- handle_transfer_exception(std::current_exception(), is_daemon_trusted());
+ handle_transfer_exception(std::current_exception(), m_wallet->is_trusted_daemon());
}
catch (...)
{
@@ -5729,7 +5871,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;
@@ -5794,7 +5937,7 @@ bool simple_wallet::submit_transfer(const std::vector<std::string> &args_)
}
catch (const std::exception& e)
{
- handle_transfer_exception(std::current_exception(), is_daemon_trusted());
+ handle_transfer_exception(std::current_exception(), m_wallet->is_trusted_daemon());
}
catch (...)
{
@@ -5818,7 +5961,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))
@@ -5827,7 +5969,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;
@@ -5932,7 +6074,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
{
@@ -6147,7 +6289,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
{
@@ -6242,9 +6384,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
{
@@ -6345,7 +6485,7 @@ static std::string get_human_readable_timespan(std::chrono::seconds seconds)
if (ts < 3600 * 24 * 30.5)
return std::to_string((uint64_t)(ts / (3600 * 24))) + tr(" days");
if (ts < 3600 * 24 * 365.25)
- return std::to_string((uint64_t)(ts / (3600 * 24 * 365.25))) + tr(" months");
+ return std::to_string((uint64_t)(ts / (3600 * 24 * 30.5))) + tr(" months");
return tr("a long time");
}
//----------------------------------------------------------------------------------------------------
@@ -6497,6 +6637,9 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
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);
@@ -6680,6 +6823,14 @@ bool simple_wallet::unspent_outputs(const std::vector<std::string> &args_)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::rescan_blockchain(const std::vector<std::string> &args_)
{
+ message_writer() << tr("Warning: this will lose any information which can not be recovered from the blockchain.");
+ message_writer() << tr("This includes destination addresses, tx secret keys, tx notes, etc");
+ std::string confirm = input_line(tr("Rescan anyway ? (Y/Yes/N/No): "));
+ if(!std::cin.eof())
+ {
+ if (!command_line::is_yes(confirm))
+ return true;
+ }
return refresh_main(0, true);
}
//----------------------------------------------------------------------------------------------------
@@ -6699,7 +6850,7 @@ void simple_wallet::wallet_idle_thread()
{
uint64_t fetched_blocks;
if (try_connect_to_daemon(true))
- m_wallet->refresh(is_daemon_trusted(), 0, fetched_blocks);
+ m_wallet->refresh(m_wallet->is_trusted_daemon(), 0, fetched_blocks);
}
catch(...) {}
m_auto_refresh_refreshing = false;
@@ -7345,7 +7496,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);
@@ -7414,14 +7566,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;
@@ -7446,7 +7598,7 @@ bool simple_wallet::import_key_images(const std::vector<std::string> &args)
fail_msg_writer() << tr("command not supported by HW wallet");
return true;
}
- if (!is_daemon_trusted())
+ if (!m_wallet->is_trusted_daemon())
{
fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
return true;
@@ -7493,12 +7645,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();
@@ -7544,7 +7696,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";
}
@@ -7777,8 +7929,6 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_params, arg_restore_multisig_wallet );
command_line::add_arg(desc_params, arg_non_deterministic );
command_line::add_arg(desc_params, arg_electrum_seed );
- command_line::add_arg(desc_params, arg_trusted_daemon);
- command_line::add_arg(desc_params, arg_untrusted_daemon);
command_line::add_arg(desc_params, arg_allow_mismatched_daemon_version);
command_line::add_arg(desc_params, arg_restore_height);
command_line::add_arg(desc_params, arg_do_not_relay);
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 472ad0c00..bfbe633ac 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
@@ -96,7 +97,7 @@ namespace cryptonote
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);
boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm,
- const std::string &multisig_keys, const std::string &old_language);
+ 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();
@@ -232,13 +233,12 @@ namespace cryptonote
bool print_ring_members(const std::vector<tools::wallet2::pending_tx>& ptx_vector, std::ostream& ostr);
std::string get_prompt() const;
bool print_seed(bool encrypted);
- bool is_daemon_trusted() const { return *m_trusted_daemon; }
/*!
* \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.
@@ -261,6 +261,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;
@@ -329,13 +330,12 @@ 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
bool m_restore_multisig_wallet; // recover flag
bool m_non_deterministic; // old 2-random generation
- boost::optional<bool> m_trusted_daemon;
bool m_allow_mismatched_daemon_version;
bool m_restoring; // are we restoring, by whatever method?
uint64_t m_restore_height; // optional