fix(chat,rpc): address adversarial review of the chat backlog
Four confirmed findings from the review pass: SECURITY — B7 was incomplete: - The single-key Export dialog (key_export_dialog) still used plain call() for z_exportkey/dumpprivkey/z_exportviewingkey — a live spending-key leak on the most common per-address export path, missed by the B7 commit. - callSecret() zeros the raw body but the parsed json holds its OWN heap copy of the secret; several callers did .get<string>() on a temporary json and freed that copy un-wiped. Fix: add RPCClient::callSecretString() — returns the bare-string result with BOTH the raw body AND the json node zeroed, so callers can't forget. Route key_export_dialog (×2), exportPrivateKey, and export_all_keys (×2) through it; scrub the z_exportmnemonic json node in seed_wallet_creator (object result); also wipe the transient key copies, the displayed s_key on reset, and the aggregated export-all `keys` buffer. CHAT: - Jump-to-latest pill: SetCursorScreenPos moved the parent cursor and never restored it, so the composer footer rendered ~8px too high while scrolled up. Save + restore the cursor around the pill. - New-message toast: gating on a chatUnreadCount() watermark delta could be swallowed when an outgoing echo (wall-clock) pushed the seen-watermark past a later reply's block time. ingest() now reports the cids it appended; the toast fires when any is a non-muted conversation — skew-proof, still mute-aware. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
#include "key_export_dialog.h"
|
||||
#include "../../app.h"
|
||||
#include "../../wallet/lite_wallet_controller.h"
|
||||
#include <sodium.h> // sodium_memzero — wipe transient secret copies (B7)
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "../../rpc/rpc_client.h"
|
||||
#include "../../rpc/rpc_worker.h"
|
||||
@@ -49,7 +50,7 @@ void KeyExportDialog::show(const std::string& address, KeyType type)
|
||||
releaseQr();
|
||||
s_key_type = type;
|
||||
s_address = address;
|
||||
s_key.clear();
|
||||
wallet::secureWipeLiteSecret(s_key); // zero any prior secret before reuse
|
||||
s_error.clear();
|
||||
}
|
||||
|
||||
@@ -62,7 +63,7 @@ void KeyExportDialog::hide()
|
||||
{
|
||||
s_open = false;
|
||||
s_fetching = false;
|
||||
s_key.clear();
|
||||
wallet::secureWipeLiteSecret(s_key); // zero the displayed secret, don't just drop the buffer
|
||||
s_show_key = false;
|
||||
s_error.clear();
|
||||
releaseQr();
|
||||
@@ -187,18 +188,18 @@ void KeyExportDialog::render(App* app)
|
||||
std::string error;
|
||||
try {
|
||||
rpc::RPCClient::TraceScope trace("Settings / Export key");
|
||||
auto result = rpc->call(method, {addr});
|
||||
key = result.get<std::string>();
|
||||
key = rpc->callSecretString(method, {addr}); // scrubs raw body + json node (B7)
|
||||
} catch (const std::exception& e) {
|
||||
error = e.what();
|
||||
}
|
||||
return [key, error]() {
|
||||
return [key = std::move(key), error]() mutable {
|
||||
if (error.empty()) {
|
||||
s_key = key;
|
||||
s_show_key = false; // Don't show by default
|
||||
} else {
|
||||
s_error = error;
|
||||
}
|
||||
if (!key.empty()) sodium_memzero(&key[0], key.size()); // wipe the last transient copy
|
||||
s_fetching = false;
|
||||
};
|
||||
});
|
||||
@@ -213,18 +214,18 @@ void KeyExportDialog::render(App* app)
|
||||
std::string error;
|
||||
try {
|
||||
rpc::RPCClient::TraceScope trace("Settings / Export viewing key");
|
||||
auto result = rpc->call("z_exportviewingkey", {addr});
|
||||
key = result.get<std::string>();
|
||||
key = rpc->callSecretString("z_exportviewingkey", {addr}); // scrubs raw body + json node (B7)
|
||||
} catch (const std::exception& e) {
|
||||
error = e.what();
|
||||
}
|
||||
return [key, error]() {
|
||||
return [key = std::move(key), error]() mutable {
|
||||
if (error.empty()) {
|
||||
s_key = key;
|
||||
s_show_key = true; // Viewing keys are less sensitive
|
||||
} else {
|
||||
s_error = error;
|
||||
}
|
||||
if (!key.empty()) sodium_memzero(&key[0], key.size()); // wipe the last transient copy
|
||||
s_fetching = false;
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user