simplewallet: allow closing wallet when locked due to inactivity
What changed, and why it matters
This change fixes a small user-experience bug in Monero's command-line wallet. Previously, if the wallet locked itself after a period of inactivity and the user tried to close it (for example by pressing Ctrl-C while being asked for the password), the program would keep looping and asking for the password, making it hard to exit. Now, when the password prompt is interrupted, the wallet closes cleanly instead.
No urgent security action required. Treat as a normal bug-fix/UX improvement. Users running `monero-wallet-cli` may benefit from the improved exit behavior after upgrading.
Security signals we found
Denial-of-service/lockout usability issue mitigated: user can now exit a locked wallet session when password input is interrupted
No cryptographic, network, or consensus changes
No privilege escalation, memory safety, or authentication bypass
Evidence from the diff
The patch modifies simplewallet::get_and_verify_password() to optionally report whether password input failed due to a read/interrupt, and modifies simplewallet::check_for_inactivity_lock() to detect that condition and call stop() rather than continuing the unlock loop. It is a defensive hardening/UX fix, not a cryptographic or consensus vulnerability.
Changed components
src/simplewallet/simplewallet.cppsrc/simplewallet/simplewallet.hInspect captured patch +16 / −3
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index cdadcc5..f94500f 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -4618,14 +4618,18 @@ std::string simple_wallet::get_mnemonic_language()
return language_list_self[language_number];
}
//----------------------------------------------------------------------------------------------------
-boost::optional<tools::password_container> simple_wallet::get_and_verify_password() const
+boost::optional<tools::password_container> simple_wallet::get_and_verify_password(bool *read_failed) const
{
+ if (read_failed) *read_failed = false;
const bool verify = m_wallet_file.empty();
auto pwd_container = (m_wallet->is_background_wallet() && m_wallet->background_sync_type() == tools::wallet2::BackgroundSyncCustomPassword)
? background_sync_cache_password_prompter(verify)
: default_password_prompter(verify);
if (!pwd_container)
+ {
+ if (read_failed) *read_failed = true;
return boost::none;
+ }
if (!m_wallet->verify_password(pwd_container->password()))
{
@@ -6208,6 +6212,7 @@ bool simple_wallet::prompt_if_old(const std::vector<tools::wallet2::pending_tx>
//----------------------------------------------------------------------------------------------------
void simple_wallet::check_for_inactivity_lock(bool user)
{
+ bool close_wallet = false;
if (m_locked)
{
#ifdef HAVE_READLINE
@@ -6269,7 +6274,8 @@ void simple_wallet::check_for_inactivity_lock(bool user)
}
try
{
- const auto pwd_container = get_and_verify_password();
+ bool read_failed = false;
+ const auto pwd_container = get_and_verify_password(&read_failed);
if (pwd_container)
{
if (started_background_sync)
@@ -6279,6 +6285,12 @@ void simple_wallet::check_for_inactivity_lock(bool user)
}
break;
}
+ if (read_failed)
+ {
+ // Password read was interrupted; close the wallet instead of looping back to the prompt
+ close_wallet = true;
+ break;
+ }
}
catch (const std::exception &e)
{
@@ -6297,6 +6309,7 @@ void simple_wallet::check_for_inactivity_lock(bool user)
m_in_command = false;
m_locked = false;
}
+ if (close_wallet) stop();
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::on_command(bool (simple_wallet::*cmd)(const std::vector<std::string>&), const std::vector<std::string> &args)
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 54c4e00..1d1ac8a 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -94,7 +94,7 @@ namespace cryptonote
void wallet_idle_thread();
//! \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;
+ boost::optional<tools::password_container> get_and_verify_password(bool *read_failed = nullptr) const;
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);
Why this scored 23/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.