From 90df19b8b64d04947c2f582dee8f15990a9ed3d0 Mon Sep 17 00:00:00 2001 From: DanS Date: Tue, 14 Jul 2026 12:02:11 -0500 Subject: [PATCH] feat(settings): redesign the remove-encryption (decrypt) modal onto reference design MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migrate App::renderDecryptWalletDialog ("Remove Wallet Encryption") onto the settings-modal reference design — presentation-only for a fund-critical dialog, plus one deliberate secret-hygiene addition: - struct-form BeginOverlayDialog(OverlayDialogSpec{BlurFloat, cardWidth 480, idSuffix "decrypt"}) replacing the legacy positional overload - Phase 0 amber TextWrapped warning -> material::DialogWarningHeader(decrypt_warning) - drop the redundant Phase 0 Separator - every rendered-chrome string across all 4 phases (PassphraseEntry / Working / Success / Error) -> TR() (14 new decrypt_*/try_again keys added to the English source + all 8 res/lang/*.json additively; the button reuses settings_remove_encryption, the label reuses change_pass_current, cancel/close reused) - HARDENING: wipe decrypt_pass_buf_ on BlurFloat dismiss (X/Esc/outside-click), mirroring the change-passphrase fix; canClose() gates pOpen so this cannot fire during the Working phase The fund-moving async worker pyramid (unlock -> export -> stop -> backup -> restart -> re-import, vault/PIN cleanup) is byte-for-byte unchanged; the three in-worker toast notifications and the "Incorrect passphrase" status are left in English to avoid touching the fund path (a separate service-layer i18n pass). Verified: build + ctest + hygiene clean; i18n complete in 8 langs with no format specifiers and the wallet.dat.encrypted.bak literal preserved; a 3-lens adversarial review (secret-hygiene / fund-path-untouched / ui-i18n) returned zero findings, with the fund-path lens proving the async pyramid diffs IDENTICAL against HEAD. Co-Authored-By: Claude Opus 4.8 (1M context) --- res/lang/de.json | 14 ++++++++++ res/lang/es.json | 14 ++++++++++ res/lang/fr.json | 14 ++++++++++ res/lang/ja.json | 14 ++++++++++ res/lang/ko.json | 14 ++++++++++ res/lang/pt.json | 14 ++++++++++ res/lang/ru.json | 14 ++++++++++ res/lang/zh.json | 14 ++++++++++ src/app_security.cpp | 62 ++++++++++++++++++++++---------------------- src/util/i18n.cpp | 15 +++++++++++ 10 files changed, 158 insertions(+), 31 deletions(-) diff --git a/res/lang/de.json b/res/lang/de.json index 5c55191..53f19f7 100644 --- a/res/lang/de.json +++ b/res/lang/de.json @@ -333,6 +333,19 @@ "date": "Datum", "date_label": "Datum:", "debug_logging": "FEHLERPROTOKOLLIERUNG", + "decrypt_desc": "Die Wallet wird exportiert, der Daemon mit einer frischen, unverschlüsselten Wallet neu gestartet und alle Schlüssel werden erneut importiert. Je nach Wallet-Größe kann dies einige Minuten dauern.", + "decrypt_error_title": "Entschlüsselung fehlgeschlagen", + "decrypt_step_backup": "Verschlüsselte Wallet wird gesichert", + "decrypt_step_export": "Wallet-Schlüssel werden exportiert", + "decrypt_step_restart": "Daemon wird neu gestartet", + "decrypt_step_stop": "Daemon wird gestoppt", + "decrypt_step_unlock": "Wallet wird entsperrt", + "decrypt_success_desc": "Ihre Wallet ist jetzt unverschlüsselt. Eine Sicherung der verschlüsselten Wallet wurde als wallet.dat.encrypted.bak in Ihrem Datenverzeichnis gespeichert.", + "decrypt_success_title": "Wallet erfolgreich entschlüsselt!", + "decrypt_title": "Wallet-Verschlüsselung entfernen", + "decrypt_wait_general": "Bitte warten. Der Daemon exportiert Schlüssel, startet neu und importiert erneut. Dies kann einige Minuten dauern.", + "decrypt_wait_restart": "Warten, bis der Daemon vollständig gestartet ist...", + "decrypt_warning": "Dadurch wird die Verschlüsselung Ihrer Wallet entfernt. Ihre privaten Schlüssel werden ungeschützt auf der Festplatte gespeichert.", "delete": "Löschen", "delete_blockchain": "Blockchain löschen", "delete_blockchain_confirm": "Löschen & Neu synchronisieren", @@ -1269,6 +1282,7 @@ "transfer_to": "Überweisen an:", "transparent": "Transparent", "transparent_address": "Transparente Adresse", + "try_again": "Erneut versuchen", "tt_addr_url": "Basis-URL zum Anzeigen von Adressen in einem Block-Explorer", "tt_address_book": "Gespeicherte Adressen für schnelles Senden verwalten", "tt_auto_lock": "Wallet nach dieser Inaktivitätszeit sperren", diff --git a/res/lang/es.json b/res/lang/es.json index abd3927..e117346 100644 --- a/res/lang/es.json +++ b/res/lang/es.json @@ -333,6 +333,19 @@ "date": "Fecha", "date_label": "Fecha:", "debug_logging": "REGISTRO DE DEPURACIÓN", + "decrypt_desc": "Se exportará el monedero, se reiniciará el daemon con un monedero nuevo sin cifrar y se reimportarán todas las claves. Esto puede tardar varios minutos según el tamaño del monedero.", + "decrypt_error_title": "Error al descifrar", + "decrypt_step_backup": "Respaldando el monedero cifrado", + "decrypt_step_export": "Exportando las claves del monedero", + "decrypt_step_restart": "Reiniciando el daemon", + "decrypt_step_stop": "Deteniendo el daemon", + "decrypt_step_unlock": "Desbloqueando el monedero", + "decrypt_success_desc": "Tu monedero ahora está sin cifrar. Se guardó una copia de seguridad del monedero cifrado como wallet.dat.encrypted.bak en tu directorio de datos.", + "decrypt_success_title": "¡Monedero descifrado correctamente!", + "decrypt_title": "Quitar el cifrado del monedero", + "decrypt_wait_general": "Espera. El daemon está exportando claves, reiniciando y reimportando. Esto puede tardar varios minutos.", + "decrypt_wait_restart": "Esperando a que el daemon termine de iniciarse...", + "decrypt_warning": "Esto quitará el cifrado de tu monedero. Tus claves privadas se almacenarán sin protección en el disco.", "delete": "Eliminar", "delete_blockchain": "Eliminar Blockchain", "delete_blockchain_confirm": "Eliminar y Resincronizar", @@ -1269,6 +1282,7 @@ "transfer_to": "Transferir a:", "transparent": "Transparente", "transparent_address": "Dirección Transparente", + "try_again": "Reintentar", "tt_addr_url": "URL base para ver direcciones en un explorador de bloques", "tt_address_book": "Administrar direcciones guardadas para envío rápido", "tt_auto_lock": "Bloquear billetera después de este tiempo de inactividad", diff --git a/res/lang/fr.json b/res/lang/fr.json index 913cb37..20a7735 100644 --- a/res/lang/fr.json +++ b/res/lang/fr.json @@ -333,6 +333,19 @@ "date": "Date", "date_label": "Date :", "debug_logging": "JOURNALISATION DE DÉBOGAGE", + "decrypt_desc": "Le portefeuille sera exporté, le daemon redémarré avec un nouveau portefeuille non chiffré, et toutes les clés réimportées. Cela peut prendre plusieurs minutes selon la taille du portefeuille.", + "decrypt_error_title": "Échec du déchiffrement", + "decrypt_step_backup": "Sauvegarde du portefeuille chiffré", + "decrypt_step_export": "Exportation des clés du portefeuille", + "decrypt_step_restart": "Redémarrage du daemon", + "decrypt_step_stop": "Arrêt du daemon", + "decrypt_step_unlock": "Déverrouillage du portefeuille", + "decrypt_success_desc": "Votre portefeuille est maintenant non chiffré. Une sauvegarde du portefeuille chiffré a été enregistrée sous wallet.dat.encrypted.bak dans votre répertoire de données.", + "decrypt_success_title": "Portefeuille déchiffré avec succès !", + "decrypt_title": "Supprimer le chiffrement du portefeuille", + "decrypt_wait_general": "Veuillez patienter. Le daemon exporte les clés, redémarre et réimporte. Cela peut prendre plusieurs minutes.", + "decrypt_wait_restart": "En attente du démarrage complet du daemon...", + "decrypt_warning": "Cela supprimera le chiffrement de votre portefeuille. Vos clés privées seront stockées sans protection sur le disque.", "delete": "Supprimer", "delete_blockchain": "Supprimer Blockchain", "delete_blockchain_confirm": "Supprimer & Resynchroniser", @@ -1269,6 +1282,7 @@ "transfer_to": "Transférer à :", "transparent": "Transparent", "transparent_address": "Adresse transparente", + "try_again": "Réessayer", "tt_addr_url": "URL de base pour consulter les adresses dans un explorateur de blocs", "tt_address_book": "Gérer les adresses enregistrées pour un envoi rapide", "tt_auto_lock": "Verrouiller le portefeuille après cette durée d'inactivité", diff --git a/res/lang/ja.json b/res/lang/ja.json index 213b4d6..e937ee9 100644 --- a/res/lang/ja.json +++ b/res/lang/ja.json @@ -333,6 +333,19 @@ "date": "日付", "date_label": "日付:", "debug_logging": "デバッグログ", + "decrypt_desc": "ウォレットがエクスポートされ、デーモンが新しい暗号化されていないウォレットで再起動し、すべての鍵が再インポートされます。ウォレットのサイズによっては数分かかる場合があります。", + "decrypt_error_title": "復号に失敗しました", + "decrypt_step_backup": "暗号化されたウォレットをバックアップしています", + "decrypt_step_export": "ウォレットの鍵をエクスポートしています", + "decrypt_step_restart": "デーモンを再起動しています", + "decrypt_step_stop": "デーモンを停止しています", + "decrypt_step_unlock": "ウォレットのロックを解除しています", + "decrypt_success_desc": "ウォレットは暗号化されていない状態になりました。暗号化されたウォレットのバックアップが、データディレクトリに wallet.dat.encrypted.bak として保存されました。", + "decrypt_success_title": "ウォレットの復号に成功しました!", + "decrypt_title": "ウォレットの暗号化を解除", + "decrypt_wait_general": "お待ちください。デーモンが鍵をエクスポートし、再起動して再インポートしています。数分かかる場合があります。", + "decrypt_wait_restart": "デーモンの起動が完了するのを待っています...", + "decrypt_warning": "ウォレットの暗号化が解除されます。秘密鍵は保護されずにディスクに保存されます。", "delete": "削除", "delete_blockchain": "ブロックチェーンを削除", "delete_blockchain_confirm": "削除して再同期", @@ -1269,6 +1282,7 @@ "transfer_to": "送金先:", "transparent": "透明", "transparent_address": "トランスペアレントアドレス", + "try_again": "再試行", "tt_addr_url": "ブロックエクスプローラーでアドレスを表示するためのベース URL", "tt_address_book": "クイック送信用の保存済みアドレスを管理", "tt_auto_lock": "この無操作時間後にウォレットをロック", diff --git a/res/lang/ko.json b/res/lang/ko.json index 63cce93..2833616 100644 --- a/res/lang/ko.json +++ b/res/lang/ko.json @@ -333,6 +333,19 @@ "date": "날짜", "date_label": "날짜:", "debug_logging": "디버그 로깅", + "decrypt_desc": "지갑을 내보내고 데몬을 새 암호화되지 않은 지갑으로 다시 시작한 후 모든 키를 다시 가져옵니다. 지갑 크기에 따라 몇 분 정도 걸릴 수 있습니다.", + "decrypt_error_title": "복호화 실패", + "decrypt_step_backup": "암호화된 지갑 백업 중", + "decrypt_step_export": "지갑 키 내보내는 중", + "decrypt_step_restart": "데몬 다시 시작 중", + "decrypt_step_stop": "데몬 중지 중", + "decrypt_step_unlock": "지갑 잠금 해제 중", + "decrypt_success_desc": "이제 지갑이 암호화되지 않았습니다. 암호화된 지갑의 백업이 데이터 디렉터리에 wallet.dat.encrypted.bak로 저장되었습니다.", + "decrypt_success_title": "지갑 복호화에 성공했습니다!", + "decrypt_title": "지갑 암호화 제거", + "decrypt_wait_general": "잠시 기다려 주세요. 데몬이 키를 내보내고 다시 시작한 후 다시 가져오고 있습니다. 몇 분 정도 걸릴 수 있습니다.", + "decrypt_wait_restart": "데몬이 완전히 시작될 때까지 기다리는 중...", + "decrypt_warning": "지갑의 암호화가 제거됩니다. 개인 키가 보호되지 않은 상태로 디스크에 저장됩니다.", "delete": "삭제", "delete_blockchain": "블록체인 삭제", "delete_blockchain_confirm": "삭제 후 재동기화", @@ -1269,6 +1282,7 @@ "transfer_to": "이체 대상:", "transparent": "투명", "transparent_address": "투명 주소", + "try_again": "다시 시도", "tt_addr_url": "블록 탐색기에서 주소를 보기 위한 기본 URL", "tt_address_book": "빠른 전송을 위해 저장된 주소 관리", "tt_auto_lock": "이 비활성 시간 후 지갑 잠금", diff --git a/res/lang/pt.json b/res/lang/pt.json index 7056532..88dd9a6 100644 --- a/res/lang/pt.json +++ b/res/lang/pt.json @@ -333,6 +333,19 @@ "date": "Data", "date_label": "Data:", "debug_logging": "REGISTRO DE DEPURAÇÃO", + "decrypt_desc": "A carteira será exportada, o daemon reiniciado com uma nova carteira sem criptografia e todas as chaves reimportadas. Isso pode levar alguns minutos, dependendo do tamanho da carteira.", + "decrypt_error_title": "Falha na descriptografia", + "decrypt_step_backup": "Fazendo backup da carteira criptografada", + "decrypt_step_export": "Exportando as chaves da carteira", + "decrypt_step_restart": "Reiniciando o daemon", + "decrypt_step_stop": "Parando o daemon", + "decrypt_step_unlock": "Desbloqueando a carteira", + "decrypt_success_desc": "Sua carteira agora está sem criptografia. Um backup da carteira criptografada foi salvo como wallet.dat.encrypted.bak no seu diretório de dados.", + "decrypt_success_title": "Carteira descriptografada com sucesso!", + "decrypt_title": "Remover criptografia da carteira", + "decrypt_wait_general": "Aguarde. O daemon está exportando chaves, reiniciando e reimportando. Isso pode levar alguns minutos.", + "decrypt_wait_restart": "Aguardando o daemon terminar de iniciar...", + "decrypt_warning": "Isso removerá a criptografia da sua carteira. Suas chaves privadas serão armazenadas sem proteção no disco.", "delete": "Excluir", "delete_blockchain": "Excluir Blockchain", "delete_blockchain_confirm": "Excluir e Ressincronizar", @@ -1269,6 +1282,7 @@ "transfer_to": "Transferir para:", "transparent": "Transparente", "transparent_address": "Endereço Transparente", + "try_again": "Tentar novamente", "tt_addr_url": "URL base para visualizar endereços em um explorador de blocos", "tt_address_book": "Gerenciar endereços salvos para envio rápido", "tt_auto_lock": "Bloquear carteira após este tempo de inatividade", diff --git a/res/lang/ru.json b/res/lang/ru.json index 3afb7a0..c1a9c66 100644 --- a/res/lang/ru.json +++ b/res/lang/ru.json @@ -333,6 +333,19 @@ "date": "Дата", "date_label": "Дата:", "debug_logging": "ЖУРНАЛ ОТЛАДКИ", + "decrypt_desc": "Кошелёк будет экспортирован, демон перезапущен с новым незашифрованным кошельком, и все ключи будут повторно импортированы. Это может занять несколько минут в зависимости от размера кошелька.", + "decrypt_error_title": "Не удалось расшифровать", + "decrypt_step_backup": "Резервное копирование зашифрованного кошелька", + "decrypt_step_export": "Экспорт ключей кошелька", + "decrypt_step_restart": "Перезапуск демона", + "decrypt_step_stop": "Остановка демона", + "decrypt_step_unlock": "Разблокировка кошелька", + "decrypt_success_desc": "Ваш кошелёк теперь не зашифрован. Резервная копия зашифрованного кошелька сохранена как wallet.dat.encrypted.bak в вашем каталоге данных.", + "decrypt_success_title": "Кошелёк успешно расшифрован!", + "decrypt_title": "Удалить шифрование кошелька", + "decrypt_wait_general": "Пожалуйста, подождите. Демон экспортирует ключи, перезапускается и повторно импортирует. Это может занять несколько минут.", + "decrypt_wait_restart": "Ожидание полного запуска демона...", + "decrypt_warning": "Это удалит шифрование вашего кошелька. Ваши приватные ключи будут храниться на диске без защиты.", "delete": "Удалить", "delete_blockchain": "Удалить блокчейн", "delete_blockchain_confirm": "Удалить и пересинхронизировать", @@ -1269,6 +1282,7 @@ "transfer_to": "Перевести на:", "transparent": "Прозрачный", "transparent_address": "Прозрачный адрес", + "try_again": "Повторить", "tt_addr_url": "Базовый URL для просмотра адресов в обозревателе блоков", "tt_address_book": "Управление сохранёнными адресами для быстрой отправки", "tt_auto_lock": "Заблокировать кошелёк после этого времени бездействия", diff --git a/res/lang/zh.json b/res/lang/zh.json index 5f9b487..2c63554 100644 --- a/res/lang/zh.json +++ b/res/lang/zh.json @@ -333,6 +333,19 @@ "date": "日期", "date_label": "日期:", "debug_logging": "调试日志", + "decrypt_desc": "钱包将被导出,守护进程将使用全新的未加密钱包重新启动,并重新导入所有密钥。根据钱包大小,这可能需要几分钟。", + "decrypt_error_title": "解密失败", + "decrypt_step_backup": "正在备份加密钱包", + "decrypt_step_export": "正在导出钱包密钥", + "decrypt_step_restart": "正在重启守护进程", + "decrypt_step_stop": "正在停止守护进程", + "decrypt_step_unlock": "正在解锁钱包", + "decrypt_success_desc": "您的钱包现在未加密。加密钱包的备份已保存为 wallet.dat.encrypted.bak,位于您的数据目录中。", + "decrypt_success_title": "钱包解密成功!", + "decrypt_title": "移除钱包加密", + "decrypt_wait_general": "请稍候。守护进程正在导出密钥、重启并重新导入。这可能需要几分钟。", + "decrypt_wait_restart": "正在等待守护进程完成启动...", + "decrypt_warning": "这将移除您钱包的加密。您的私钥将以未受保护的方式存储在磁盘上。", "delete": "删除", "delete_blockchain": "删除区块链", "delete_blockchain_confirm": "删除并重新同步", @@ -1269,6 +1282,7 @@ "transfer_to": "转账至:", "transparent": "透明", "transparent_address": "透明地址", + "try_again": "重试", "tt_addr_url": "在区块浏览器中查看地址的基础 URL", "tt_address_book": "管理已保存的地址以快速发送", "tt_auto_lock": "在此不活动时间后锁定钱包", diff --git a/src/app_security.cpp b/src/app_security.cpp index 8ff032f..06c197f 100644 --- a/src/app_security.cpp +++ b/src/app_security.cpp @@ -1434,26 +1434,21 @@ void App::renderDecryptWalletDialog() { bool canClose = wallet_security_workflow_.canClose(); bool* pOpen = canClose ? &show_decrypt_dialog_ : nullptr; - if (BeginOverlayDialog("Remove Wallet Encryption", pOpen, 480.0f, 0.94f)) { + OverlayDialogSpec ov; + ov.title = TR("decrypt_title"); ov.p_open = pOpen; + ov.style = OverlayStyle::BlurFloat; + ov.cardWidth = 480.0f; ov.idSuffix = "decrypt"; + if (BeginOverlayDialog(ov)) { // ---- Phase 0: Passphrase entry ---- if (decryptState.phase == DecryptPhase::PassphraseEntry) { - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1, 0.7f, 0.3f, 1)); - ImGui::TextWrapped(ICON_MD_WARNING - " This will remove encryption from your wallet. " - "Your private keys will be stored unprotected on disk."); - ImGui::PopStyleColor(); + DialogWarningHeader(TR("decrypt_warning")); ImGui::Spacing(); - ImGui::TextWrapped( - "The wallet will be exported, the daemon restarted with a fresh " - "unencrypted wallet, and all keys re-imported. This may take " - "several minutes depending on wallet size."); - ImGui::Spacing(); - ImGui::Separator(); + ImGui::TextWrapped("%s", TR("decrypt_desc")); ImGui::Spacing(); - ImGui::Text("Current Passphrase:"); + ImGui::TextUnformatted(TR("change_pass_current")); ImGui::PushItemWidth(-1); bool enterPressed = ImGui::InputText("##decrypt_pass", decrypt_pass_buf_, sizeof(decrypt_pass_buf_), ImGuiInputTextFlags_Password | @@ -1469,7 +1464,7 @@ void App::renderDecryptWalletDialog() { float btnW = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f; ImGui::BeginDisabled(!valid || decryptState.inProgress); - if (ui::material::TactileButton("Remove Encryption", ImVec2(btnW, 40)) || (enterPressed && valid)) { + if (ui::material::TactileButton(TR("settings_remove_encryption"), ImVec2(btnW, 40)) || (enterPressed && valid)) { std::string passphrase(decrypt_pass_buf_); memset(decrypt_pass_buf_, 0, sizeof(decrypt_pass_buf_)); wallet_security_workflow_.start(std::chrono::steady_clock::now()); @@ -1660,7 +1655,7 @@ void App::renderDecryptWalletDialog() { ImGui::EndDisabled(); ImGui::SameLine(); - if (ui::material::TactileButton("Cancel", ImVec2(btnW, 40))) { + if (ui::material::TactileButton(TR("cancel"), ImVec2(btnW, 40))) { memset(decrypt_pass_buf_, 0, sizeof(decrypt_pass_buf_)); show_decrypt_dialog_ = false; } @@ -1669,11 +1664,11 @@ void App::renderDecryptWalletDialog() { } else if (decryptState.phase == DecryptPhase::Working) { // Step checklist const char* stepLabels[] = { - "Unlocking wallet", - "Exporting wallet keys", - "Stopping daemon", - "Backing up encrypted wallet", - "Restarting daemon" + TR("decrypt_step_unlock"), + TR("decrypt_step_export"), + TR("decrypt_step_stop"), + TR("decrypt_step_backup"), + TR("decrypt_step_restart") }; const int numSteps = 5; @@ -1750,10 +1745,9 @@ void App::renderDecryptWalletDialog() { // Step-specific hints if (decryptState.step == DecryptStep::RestartDaemon) { - ImGui::TextWrapped("Waiting for the daemon to finish starting up..."); + ImGui::TextWrapped("%s", TR("decrypt_wait_restart")); } else { - ImGui::TextWrapped("Please wait. The daemon is exporting keys, restarting, " - "and re-importing. This may take several minutes."); + ImGui::TextWrapped("%s", TR("decrypt_wait_general")); } // Total elapsed @@ -1770,15 +1764,13 @@ void App::renderDecryptWalletDialog() { ImGui::TextColored(ImVec4(0.3f, 1.0f, 0.5f, 1.0f), ICON_MD_CHECK_CIRCLE); ImGui::PopFont(); ImGui::SameLine(); - ImGui::TextColored(ImVec4(0.3f, 1.0f, 0.5f, 1.0f), "Wallet decrypted successfully!"); + ImGui::TextColored(ImVec4(0.3f, 1.0f, 0.5f, 1.0f), "%s", TR("decrypt_success_title")); ImGui::Spacing(); - ImGui::TextWrapped( - "Your wallet is now unencrypted. A backup of the encrypted wallet " - "was saved as wallet.dat.encrypted.bak in your data directory."); + ImGui::TextWrapped("%s", TR("decrypt_success_desc")); ImGui::Spacing(); - if (ui::material::TactileButton("Close", ImVec2(-1, 40))) { + if (ui::material::TactileButton(TR("close"), ImVec2(-1, 40))) { show_decrypt_dialog_ = false; } @@ -1788,23 +1780,31 @@ void App::renderDecryptWalletDialog() { ImGui::TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), ICON_MD_ERROR); ImGui::PopFont(); ImGui::SameLine(); - ImGui::TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), "Decryption failed"); + ImGui::TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), "%s", TR("decrypt_error_title")); ImGui::Spacing(); ImGui::TextWrapped("%s", decryptState.status.c_str()); ImGui::Spacing(); float btnW = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f; - if (ui::material::TactileButton("Try Again", ImVec2(btnW, 40))) { + if (ui::material::TactileButton(TR("try_again"), ImVec2(btnW, 40))) { wallet_security_workflow_.reset(); } ImGui::SameLine(); - if (ui::material::TactileButton("Close", ImVec2(btnW, 40))) { + if (ui::material::TactileButton(TR("close"), ImVec2(btnW, 40))) { show_decrypt_dialog_ = false; } } EndOverlayDialog(); } + + // Wipe the passphrase buffer if the dialog was dismissed (X / Esc / outside- + // click) without submitting. The submit and Cancel paths already memset it; + // this covers the BlurFloat dismiss paths. (canClose is false during Working, + // so an in-flight decrypt cannot be dismissed here.) + if (!show_decrypt_dialog_) { + memset(decrypt_pass_buf_, 0, sizeof(decrypt_pass_buf_)); + } } // =========================================================================== diff --git a/src/util/i18n.cpp b/src/util/i18n.cpp index 79b68bc..5e64a0f 100644 --- a/src/util/i18n.cpp +++ b/src/util/i18n.cpp @@ -522,6 +522,21 @@ void I18n::loadBuiltinEnglish() strings_["change_pass_current"] = "Current Passphrase:"; strings_["change_pass_new"] = "New Passphrase:"; strings_["change_pass_confirm"] = "Confirm New:"; + // --- Remove-encryption (decrypt) dialog (settings) --- + strings_["decrypt_title"] = "Remove Wallet Encryption"; + strings_["decrypt_warning"] = "This will remove encryption from your wallet. Your private keys will be stored unprotected on disk."; + strings_["decrypt_desc"] = "The wallet will be exported, the daemon restarted with a fresh unencrypted wallet, and all keys re-imported. This may take several minutes depending on wallet size."; + strings_["decrypt_step_unlock"] = "Unlocking wallet"; + strings_["decrypt_step_export"] = "Exporting wallet keys"; + strings_["decrypt_step_stop"] = "Stopping daemon"; + strings_["decrypt_step_backup"] = "Backing up encrypted wallet"; + strings_["decrypt_step_restart"] = "Restarting daemon"; + strings_["decrypt_wait_restart"] = "Waiting for the daemon to finish starting up..."; + strings_["decrypt_wait_general"] = "Please wait. The daemon is exporting keys, restarting, and re-importing. This may take several minutes."; + strings_["decrypt_success_title"] = "Wallet decrypted successfully!"; + strings_["decrypt_success_desc"] = "Your wallet is now unencrypted. A backup of the encrypted wallet was saved as wallet.dat.encrypted.bak in your data directory."; + strings_["decrypt_error_title"] = "Decryption failed"; + strings_["try_again"] = "Try Again"; strings_["wiz_confirm"] = "Confirm:"; strings_["wiz_strength_weak"] = "Weak"; strings_["wiz_strength_fair"] = "Fair";