Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions src/qt/rpcconsole.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#endif // ENABLE_WALLET
#include <rpc/client.h>
#include <rpc/server.h>
#include <support/cleanse.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <util/time.h>
Expand Down Expand Up @@ -691,6 +692,85 @@ void RPCConsole::WriteCommandHistory()
settings.endArray();
}

void RPCConsole::ClearCommandHistory()
{
// Best-effort attempt to securely overwrite command history in memory.
// Note: Complete memory sanitization cannot be guaranteed with QString due to
// Qt's implicit sharing (copy-on-write) and internal memory management.
for (QString& cmd : history) {
if (cmd.isEmpty()) continue;

// Attempt to cleanse QString's internal buffer using Bitcoin Core's
// secure memory_cleanse function (uses platform-specific secure zeroing)
QChar* data = cmd.data(); // Get pointer to mutable internal buffer
size_t byte_size = cmd.size() * sizeof(QChar);

// First pass: overwrite with 'x' and cleanse
cmd.fill('x');
if (data == cmd.data()) { // Verify we still have the same buffer
memory_cleanse(cmd.data(), byte_size);
}

// Second pass: overwrite with null and cleanse
cmd.fill('\0');
if (data == cmd.data()) { // Verify we still have the same buffer
memory_cleanse(cmd.data(), byte_size);
}
}

// Overwrite saved history in settings with dummy data
QSettings settings;

// First pass: read existing commands and overwrite with dummy data of same length
QStringList dummy_commands;
int size = settings.beginReadArray("nRPCConsoleWindowHistory");
for (int i = 0; i < size; ++i) {
settings.setArrayIndex(i);
QString cmd = settings.value("cmd").toString();
// Store dummy command with same length as original (don't leak length info)
dummy_commands.append(QString(cmd.size(), 'x'));
}
settings.endArray();

// Write dummy data to overwrite the original commands
if (!dummy_commands.empty()) {
settings.beginWriteArray("nRPCConsoleWindowHistory");
for (int i = 0; i < dummy_commands.size(); ++i) {
settings.setArrayIndex(i);
settings.setValue("cmd", dummy_commands[i]);
}
settings.endArray();
settings.sync(); // Force to disk
}

// Clear the history list
history.clear();
historyPtr = 0;

// Also cleanse cmdBeforeBrowsing which may contain command data
if (!cmdBeforeBrowsing.isEmpty()) {
QChar* data = cmdBeforeBrowsing.data();
size_t byte_size = cmdBeforeBrowsing.size() * sizeof(QChar);
cmdBeforeBrowsing.fill('x');
if (data == cmdBeforeBrowsing.data()) {
memory_cleanse(cmdBeforeBrowsing.data(), byte_size);
}
cmdBeforeBrowsing.fill('\0');
if (data == cmdBeforeBrowsing.data()) {
memory_cleanse(cmdBeforeBrowsing.data(), byte_size);
}
}
cmdBeforeBrowsing.clear();

// Second pass: write empty history to settings
settings.beginWriteArray("nRPCConsoleWindowHistory");
// Empty array - no entries written
settings.endArray();

// Force settings to sync to disk
settings.sync();
}

RPCConsole::~RPCConsole()
{
QSettings settings;
Expand Down Expand Up @@ -1182,6 +1262,26 @@ void RPCConsole::on_lineEdit_returnPressed()
return;
}

// Special command to clear command history
if (cmd == QLatin1String("/clearhistory")) {
QMessageBox::StandardButton reply = QMessageBox::question(this,
tr("Clear Command History"),
tr("This will permanently clear your command history and console output.<br><br>"
"While this action is irreversible, complete removal from memory and disk "
"cannot be guaranteed due to system and Qt framework limitations.<br><br>"
"Are you sure you want to proceed?"),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::No);

if (reply == QMessageBox::Yes) {
ClearCommandHistory();
clear(false); // Clear console output too
message(CMD_REPLY, tr("Command history and console output cleared."));
}
ui->lineEdit->clear();
return;
}

if (m_is_executing) {
return;
}
Expand Down
1 change: 1 addition & 0 deletions src/qt/rpcconsole.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ public Q_SLOTS:
void startExecutor();
void setTrafficGraphRange(int mins);
void WriteCommandHistory();
void ClearCommandHistory();

enum ColumnWidths
{
Expand Down