fix(security): color seed-save by outcome; explain the Encrypt button; friendly key-export errors
- Seed-backup dialog: a failed "Save to file" was drawn in the success (green)
colour; it's now red on failure, green on success (flag reset on close).
- Encrypt-wallet dialog: the disabled Encrypt button now says why once the user
starts typing ("Use at least 8 characters." / "The passphrases don't match."),
and a "Show passphrase" checkbox reveals both fields.
- Key-export dialog: the raw RPC exception (e.g. "...walletpassphrase first")
is routed through util::friendlyRpcError(), so a locked wallet reads
"Unlock your wallet first, then try again." instead of daemon jargon.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+5
-1
@@ -4635,6 +4635,7 @@ void App::renderSeedBackupDialog()
|
|||||||
sodium_memzero(&seed_backup_phrase_[0], seed_backup_phrase_.size());
|
sodium_memzero(&seed_backup_phrase_[0], seed_backup_phrase_.size());
|
||||||
seed_backup_phrase_.clear();
|
seed_backup_phrase_.clear();
|
||||||
seed_backup_status_.clear();
|
seed_backup_status_.clear();
|
||||||
|
seed_backup_status_ok_ = true;
|
||||||
seed_backup_fetch_started_ = false;
|
seed_backup_fetch_started_ = false;
|
||||||
seed_backup_loading_ = false;
|
seed_backup_loading_ = false;
|
||||||
seed_backup_no_mnemonic_ = false;
|
seed_backup_no_mnemonic_ = false;
|
||||||
@@ -4707,7 +4708,9 @@ void App::renderSeedBackupDialog()
|
|||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
if (!seed_backup_status_.empty()) {
|
if (!seed_backup_status_.empty()) {
|
||||||
ImGui::PushTextWrapPos(0.0f);
|
ImGui::PushTextWrapPos(0.0f);
|
||||||
ImGui::TextColored(ui::material::SuccessVec4(), "%s", seed_backup_status_.c_str());
|
ImGui::TextColored(seed_backup_status_ok_ ? ui::material::SuccessVec4()
|
||||||
|
: ImVec4(0.85f, 0.33f, 0.33f, 1.0f),
|
||||||
|
"%s", seed_backup_status_.c_str());
|
||||||
ImGui::PopTextWrapPos();
|
ImGui::PopTextWrapPos();
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
}
|
}
|
||||||
@@ -4724,6 +4727,7 @@ void App::renderSeedBackupDialog()
|
|||||||
const bool ok = util::Platform::writeFileAtomically(path, content,
|
const bool ok = util::Platform::writeFileAtomically(path, content,
|
||||||
/*restrictPermissions=*/true);
|
/*restrictPermissions=*/true);
|
||||||
sodium_memzero(&content[0], content.size());
|
sodium_memzero(&content[0], content.size());
|
||||||
|
seed_backup_status_ok_ = ok; // red when the write failed (was always green before)
|
||||||
seed_backup_status_ = (ok ? std::string(TR("seed_backup_saved"))
|
seed_backup_status_ = (ok ? std::string(TR("seed_backup_saved"))
|
||||||
: std::string(TR("seed_backup_save_failed"))) + path;
|
: std::string(TR("seed_backup_save_failed"))) + path;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1402,6 +1402,7 @@ private:
|
|||||||
// mnemonic) and is wiped with sodium_memzero when the dialog closes.
|
// mnemonic) and is wiped with sodium_memzero when the dialog closes.
|
||||||
std::string seed_backup_phrase_;
|
std::string seed_backup_phrase_;
|
||||||
std::string seed_backup_status_;
|
std::string seed_backup_status_;
|
||||||
|
bool seed_backup_status_ok_ = true; // colour the status line by outcome (green save vs red fail)
|
||||||
bool seed_backup_fetch_started_ = false;
|
bool seed_backup_fetch_started_ = false;
|
||||||
bool seed_backup_loading_ = false;
|
bool seed_backup_loading_ = false;
|
||||||
bool seed_backup_no_mnemonic_ = false;
|
bool seed_backup_no_mnemonic_ = false;
|
||||||
|
|||||||
+14
-6
@@ -1452,15 +1452,16 @@ void App::renderEncryptWalletDialog() {
|
|||||||
|
|
||||||
ImGui::TextUnformatted(TR("wiz_passphrase"));
|
ImGui::TextUnformatted(TR("wiz_passphrase"));
|
||||||
ImGui::PushItemWidth(-1);
|
ImGui::PushItemWidth(-1);
|
||||||
ImGui::InputText("##enc_pass", encrypt_pass_buf_, sizeof(encrypt_pass_buf_),
|
static bool s_showEncPass = false;
|
||||||
ImGuiInputTextFlags_Password);
|
const ImGuiInputTextFlags encPwFlags = s_showEncPass ? 0 : ImGuiInputTextFlags_Password;
|
||||||
|
ImGui::InputText("##enc_pass", encrypt_pass_buf_, sizeof(encrypt_pass_buf_), encPwFlags);
|
||||||
ImGui::PopItemWidth();
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
ImGui::TextUnformatted(TR("enc_confirm"));
|
ImGui::TextUnformatted(TR("enc_confirm"));
|
||||||
ImGui::PushItemWidth(-1);
|
ImGui::PushItemWidth(-1);
|
||||||
ImGui::InputText("##enc_confirm", encrypt_confirm_buf_, sizeof(encrypt_confirm_buf_),
|
ImGui::InputText("##enc_confirm", encrypt_confirm_buf_, sizeof(encrypt_confirm_buf_), encPwFlags);
|
||||||
ImGuiInputTextFlags_Password);
|
|
||||||
ImGui::PopItemWidth();
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::Checkbox(TR("enc_show_pass"), &s_showEncPass);
|
||||||
|
|
||||||
// Strength meter bar
|
// Strength meter bar
|
||||||
{
|
{
|
||||||
@@ -1508,8 +1509,15 @@ void App::renderEncryptWalletDialog() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
bool valid = strlen(encrypt_pass_buf_) >= 8 &&
|
const size_t encPassLen = strlen(encrypt_pass_buf_);
|
||||||
strcmp(encrypt_pass_buf_, encrypt_confirm_buf_) == 0;
|
const bool encMatch = strcmp(encrypt_pass_buf_, encrypt_confirm_buf_) == 0;
|
||||||
|
bool valid = encPassLen >= 8 && encMatch;
|
||||||
|
// Say WHY the button is disabled, once the user has started typing (was silent before).
|
||||||
|
if (!valid && (encPassLen > 0 || strlen(encrypt_confirm_buf_) > 0)) {
|
||||||
|
const char* why = (encPassLen < 8) ? TR("enc_min_len")
|
||||||
|
: (!encMatch ? TR("enc_mismatch") : "");
|
||||||
|
if (*why) ImGui::TextColored(ImVec4(1.0f, 0.7f, 0.3f, 1.0f), "%s", why);
|
||||||
|
}
|
||||||
|
|
||||||
float btnW = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f;
|
float btnW = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f;
|
||||||
ImGui::BeginDisabled(!valid || encrypt_in_progress_);
|
ImGui::BeginDisabled(!valid || encrypt_in_progress_);
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ void KeyExportDialog::render(App* app)
|
|||||||
s_key = key;
|
s_key = key;
|
||||||
s_show_key = false; // Don't show by default
|
s_show_key = false; // Don't show by default
|
||||||
} else {
|
} else {
|
||||||
s_error = error;
|
s_error = util::friendlyRpcError(error);
|
||||||
}
|
}
|
||||||
if (!key.empty()) sodium_memzero(&key[0], key.size()); // wipe the last transient copy
|
if (!key.empty()) sodium_memzero(&key[0], key.size()); // wipe the last transient copy
|
||||||
s_fetching = false;
|
s_fetching = false;
|
||||||
@@ -223,7 +223,7 @@ void KeyExportDialog::render(App* app)
|
|||||||
s_key = key;
|
s_key = key;
|
||||||
s_show_key = true; // Viewing keys are less sensitive
|
s_show_key = true; // Viewing keys are less sensitive
|
||||||
} else {
|
} else {
|
||||||
s_error = error;
|
s_error = util::friendlyRpcError(error);
|
||||||
}
|
}
|
||||||
if (!key.empty()) sodium_memzero(&key[0], key.size()); // wipe the last transient copy
|
if (!key.empty()) sodium_memzero(&key[0], key.size()); // wipe the last transient copy
|
||||||
s_fetching = false;
|
s_fetching = false;
|
||||||
|
|||||||
@@ -697,6 +697,9 @@ void I18n::loadBuiltinEnglish()
|
|||||||
// --- Encrypt / change-passphrase dialogs (settings) ---
|
// --- Encrypt / change-passphrase dialogs (settings) ---
|
||||||
strings_["enc_desc"] = "Encrypting your wallet protects your private keys with a passphrase. After encryption, the daemon will restart.";
|
strings_["enc_desc"] = "Encrypting your wallet protects your private keys with a passphrase. After encryption, the daemon will restart.";
|
||||||
strings_["enc_confirm"] = "Confirm:";
|
strings_["enc_confirm"] = "Confirm:";
|
||||||
|
strings_["enc_show_pass"] = "Show passphrase";
|
||||||
|
strings_["enc_min_len"] = "Use at least 8 characters.";
|
||||||
|
strings_["enc_mismatch"] = "The passphrases don't match.";
|
||||||
strings_["enc_encrypting"] = "Encrypting wallet...";
|
strings_["enc_encrypting"] = "Encrypting wallet...";
|
||||||
strings_["enc_wait"] = "Please wait, do not close the application.";
|
strings_["enc_wait"] = "Please wait, do not close the application.";
|
||||||
strings_["enc_success"] = "Wallet encrypted successfully!";
|
strings_["enc_success"] = "Wallet encrypted successfully!";
|
||||||
|
|||||||
Reference in New Issue
Block a user